CPP notes

From OriWiki

Jump to: navigation, search

labc

labcpp

Contents

get environment variables

 
#include <cstdlib> 
int main() {
  const char *str = std::getenv("PATH");  
  std::cout << "PATH:" << str << '\n'; 
}

define a macro in the compilation command

#include <iostream> 

int main() {
  std::cout << MYDEF << '\n'; 
}
g++ -Wall -DMYDEF=17 check.cpp -o check 
g++ -Wall -D'MYDEF="hello lord"' check.cpp -o check 

this->data at initialization list

The following doesnot compile and put a question whether I should use the this->dataMember syntax

#include <iostream> 
class A {
public: 
  int m_data; 
  A()
    :m_data(5)  // the following doesn't compile: (this->m_data)(5) 
  { 
    std::cout << this->m_data << "\n"; 
  }  
}; 

int main() {
  A a; 
}

std::set

#include <iostream> 
#include <set> 
#include <string> 
#include <algorithm> 
#include <iterator> 

typedef std::set<std::string> Set; 

int main() {
  Set s; 

  s.insert("hey"); s.insert("hello");  s.insert("bye");
  copy(s.begin(),s.end(),std::ostream_iterator<std::string> (std::cout,"\n")); 

  s.erase("hello"); 

  copy(s.begin(),s.end(),std::ostream_iterator<std::string> (std::cout,", ")); 

  std::cout << "main done.\n"; 
}

ldd

ldd - list dynamic dependencies

list the linked stuff

ldd <executable>

Makefile

my guide

A minimal skeleton

 
Objs = main.o f1.o
main: $(Objs)
	g++ $(Objs) -o $@

%.o: %.cpp 
	g++ -Wall -c $< 

depend:
	echo -e '\n' >> Makefile 
	g++ -MM *.cpp >> Makefile

clean:
	rm *.o 

alternative syntax for the general rule:

.cpp.o:
	g++ -Wall -c $< 

Meta makefile

Assuming two subdirectories proj1 and proj1 that contain projects

all:
	make -C proj1
	make -C proj2
clean:
	make -C proj1 clean 
	make -C proj2 clean 

run:
	./proj1/main
	./proj2/main

uri was here

using libraries

A guide from the labc course at the university.

static library makefile skeleton

In the library directory

Objs = f1.o f2.o 

libmine.a : $(Objs) 
	ar rc $@ $(Objs) 
	ranlib $@ 
.cpp.o:
	g++ -Wall -c $< 

In the using directory

using_static_lib: using_static_lib.o 
	g++ using_static_lib.o -L../static_lib -lmine -o $@ 

using_static_lib.o: using_static_lib.cpp
	g++ -Wall -I../static_lib -c $< 

shared library makefile skeleton

Objs = f1.o f2.o 

libmine.so : $(Objs) 
	g++ -shared $(Objs) -o $@
.cpp.o:
	g++ -Wall -fPIC -c $< 

In the using directory

using_shared_lib: using_shared_lib.o 
	g++ $< -L ../shared_lib -lmine -o $@

using_shared_lib.o: using_shared_lib.cpp
	g++ -Wall -I ../shared_lib -c $< 

# note you should add the library directory to the LD_LIBRARY_PATH environment 
# variable 
# LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:`pwd`/../shared_lib

Exception Handling

Note that each throw copies the thrown object into a dedicated place:

#include <iostream> 
#include <string> 
using namespace std; 
 
class A {
  string m_str; 
public:
  A(string str): m_str(str) { std::cout << "A(), "<<m_str<<"\n"; } 
  ~A() { std::cout << "~A(), " <<m_str << "\n"; } 
  A(const A& other):m_str("copy "+other.m_str)  { 
    std::cout << "A(const A&), "<<m_str <<"\n"; 
  } 
}; 

int main() {
  std::cout << "start...\n"; 
  try {
    A a("local"); 
    throw a; 
  } catch (A a) {
    std::cout << "catch\n"; 
  } 
  std::cout << "done.\n"; 
}

Output:

start...
A(), local
A(const A&), copy local
~A(), local
A(const A&), copy copy local
catch
~A(), copy copy local
~A(), copy local
done.

It seems like the compiler (at least the compilers I've checked) performs an optimization when throwing an annonimous object:

int main() {
  std::cout << "start...\n"; 
  try {
    throw A("local"); 
  } catch (A a) {
    std::cout << "catch\n"; 
  } 
  std::cout << "done.\n"; 
}

Output

start...
A(), local
A(const A&), copy local
catch
~A(), copy local
~A(), local
done.

The sending of the parameter by name can also be saved if a refference is cought:

int main() {
  std::cout << "start...\n"; 
  try {
    throw A("local"); 
  } catch (A& a) {
    std::cout << "catch\n"; 
  } 
  std::cout << "done.\n"; 
}

Output

start...
A(), local
catch
~A(), local
done.

template stuff

It seems like there is a strange behavior of g++-3.4 stuff that is related to friend of template function declaration. See how I managed to get the following code to compile only after putting the implementation before the declaration (which required a forward declaration)

 
#include <iostream> 

template <typename T> 
class A; 

template <typename T> 
std::ostream& operator<< (std::ostream& os, const A<T>& a) {
  return os << a.m_data; 
}

template <typename T>
class A {
  friend std::ostream& ::operator << <>(std::ostream& os, const A& a); 
  T m_data; 
public:
  A(T data):m_data(data) {} 
}; 

int main() {
  A<std::string> a("hello"); 
  std::cout << a << '\n'; 
}


My smart ptr sample code

The reference counter is implemented as a dynamically allocated int that is pointed from the My_Ptr object (m_rc). A NULL My_Ptr is represented with both m_ptr and m_rc equal to NULL.Note that the dec() function is the one that performs the deletion.

#include <iostream> 
#include <string> 
using namespace std; 

template <typename T> 
class My_Ptr; 

template <typename T> 
ostream& operator<<(ostream& os, const My_Ptr<T>& ptr) {
  os << ptr.m_ptr << " RC:";
  if(ptr.m_rc)
    os << *(ptr.m_rc);
  else 
    os << "NULL"; 
  return os; 
}

template <typename T>
class My_Ptr {
  friend ostream& operator<< <>(ostream& os, const My_Ptr& ptr); 
  T *m_ptr; 
  int *m_rc;
  void inc() { 
    if(!m_rc)
      return; 
    ++(*m_rc); 
  } 
  void dec() { 
    if(!m_rc)
      return; 
    --(*m_rc);
    if(*m_rc == 0) {
      delete m_rc; 
      delete m_ptr;
      m_ptr = NULL; 
      m_rc = NULL; 
    }
  }
public:
  My_Ptr():m_ptr(NULL),m_rc(NULL) {} 
  My_Ptr(T* ptr): m_ptr(ptr),m_rc(new int(1)) {} 
  My_Ptr(const My_Ptr<T>& other): m_ptr(other.m_ptr), m_rc(other.m_rc) { inc(); }
  ~My_Ptr() { dec(); }
  void operator =(My_Ptr<T>& other) {
    other.inc();  //  
    dec();        // order matters for p=p case 
    m_rc = other.m_rc; 
    m_ptr = other.m_ptr; 
  } 
}; 


class A {
  string m_data; 
public:
  A(string data):m_data(data) { cout << "A(), " << m_data << '\n'; } 
  ~A() { cout << "~A(), " << m_data << '\n'; } 
}; 

int main() {
  My_Ptr<A> p, pp(new A("***")); 
  {
    My_Ptr<A> p1(new A("@@@"));
    p = p1; 
    cout << "1 " << p << " " << p1 << '\n'; 
    {
      My_Ptr<A> p2(p1);
      cout << "2 " << p << " " << p1 << " " << p2 << '\n'; 
    }
    cout << "3 " << p << " " << p1 << '\n'; 
  }

  pp = p; 
  std::cout << "4 " << p << '\n'; 
} 

(this code seems to give similar functionality as boost::shared_ptr [1])

enum

Usual definition

enum Day_t {
  Sunday, 
  Monday, 
  Tuesday, 
  DAY_T_LAST,
}; 
int main() {
  Day_t day; 
  day = Monday; 
  int N = DAY_T_LAST; 
  std::cout << "there are " << N << " days. day=" << day << '\n'; 
}

I've seen codes that add a typedef before:

typedef enum Day_t {...};

Which seems to have no effect.

view symbols in shared object

nm libmylib.so
Personal tools