C++ FAQ for myself


Oh! hash_map

Just that!
--- Marvin (The Hitchhiker's guide to the galaxy)

Why do you use hash_map?
--- J.H.


Sort with STL

LessThan Comparable means there is operator<() available. And partial ordering is OK. Strict Weak Ordering is more strict than this condition. Total ordering is more strict than Strict Weak Ordering.

/**
   vector< LTCtype > V;  // LTC ... Less than comparable.
   ...
   sort(V.begin(), V.end(), less_LTC());
*/
struct less_LTC : public std::binary_function< LTCtype, LTCtype, bool > {
  bool operator()(const LTCtype& x, const LTCtype& y) {
    return((x.d_index) < (y.d_index)); // just an example
  }
};

Binary search with STL

class BSElem {
public:
  BSElem(int i) : d_index(i) {};
public:
  int d_index;
};

std::vector< BSElem > v;
...
std::sort(v.begin(), v.end(), less_LTC());
...
BSElem tolookup(i);
std::binary_search(v.begin(), v.end(), tolookup, less_LTC())) ? "found" : "not found";

const reverse iterator of STL

const_reverse_iterator is not so symmetric with const_iterator. When you have next code,
  list< int > alist;
  for(int i = 0; i < 4; i++){
     alist.push_back(i);
  }
You can compile:
  for(list< int >::const_iterator ii = alist.begin();
      ii != alist.end(); ++ii){
    cout << *ii << " ";
  }
But, you cannot compile:
  for(list< int >::const_reverse_iterator ii = alist.rbegin();
      ii != alist.rend(); ++ii){
    cout << *ii << " ";
  }
because of next compilation error (in the case of gcc).
  riter.cc:71: error: no match for 'operator!=' in 'ri != std::list<_Tp,
     _Alloc>::rend() [with _Tp = int, _Alloc = std::allocator]()'
This is surprising, isn't it? Just I change the iterator -> reverse_iterator, begin() -> rbegin(), and end() -> rend(). The reason is so complicated. One is const and non-const does not need the same type by ANSI C++ standard. This means,
  int a = 3;
  if (a == 4){} // This line can be error since a is non const and 4 is const.

But I think this error may not happend. But, STL implementation, the rbegin() and rend() is iterator's template class and (forward) iterator is not. So, this is really not comparable. Other problem is also in the compiler's assumption of which constructor should be chosen. The rbegin() is copy constructed to const_reverse_iterator, so alist.rbegin() can know it should be const. But what can rend() should be? If alist is not const. The overload of returning value only does not work in C++, e.g., overloading int f() and double f() are not permitted. So, rend() here just return the non-const version, since alist is non-const.

To tell (or trick) this to the compiler, you can cast to const, but DO NOT call constructor, since it copy's the whole list and you want to make an iterator of the copy of the list. So, cast to reference to the const version. Then,

  for(list< int >::const_reverse_iterator ii = alist.rbegin();
      ii != ((const list< int >& )alist).rend(); ++ii){
    cout << *ii << " ";
  }

it works! But, hey, please C++.


C++ namespace Oh my!, namespace alias.

Namespace function is usually logical grouping of the names. But it is also an identifier of the space.

Java has a nice convention which can give you an unique namespace. This is great. Like in my case, de.mpg.mpi-sb.ag4.yhitoshi could give me almost unique name on the Internet. Moreover, java's class name and filename correspondence support this uniqueness. Both uniqueness and logcal grouping are here.

However, C++ has totally lost the uniqueness. You can make any namespace which has the same name but different groups. Almost everyone in graphics make own Math namespace and inside this namespace Vector and Matrix are there. Oh my.

To make this uniqueness worser, C++ has a function to make namespace alias. Which is in C++ programming language 3rd Edition section 8.2.7, after the section 8.2.5 Avoiding name clashes.

namespace MPII {} // is short and may clash.
namespace MaxPlanckInstituteFuerInformatik {} // is long.
namespace MPII = MaxPlanckInstituteFuerInformatik {} // alias like this.

One thing C++ book said is you can use like symbolic link. You have several version namespace, and just choose one.

namespace MaxPlanckInstitute_GMU_v1_0_0 {} // version 1.0.0
namespace MaxPlanckInstitute_GMU_v1_1_0 {} // version 1.1.0
namespace MaxPlanckInstitute_GMU_v1_2_0 {} // version 1.2.0
namespace MPII = MaxPlanckInstitute_GMU_v1_2_0 {} // use 1.2.0 by alias

Yes. This is somehow make sense. But I think this is too complicated. And the last line of the C++ book's this section is:

On the other hand, overuse of aliases (of any kind) can lead to confusion.


C++ namespace Oh my!, Unnamed namespace.

There is somehow nice idea of anonymous name like lambda in Lisp. If you use a name only once, why you need make a name with being afraid about name clash. But this Unname namespace is I do not know whether it is really useful or not (but I would rather say no).

Unnamed namespace is not extern, so usage is in one file. We have already static. If you will clash a name in one file, I will rather make two files and make them static. The example of Unnamed name space in C++ book is:

// in FileA.cc
namespace {
   int  a;
   void f(){ /* implementation I using a. */ }
   int  g(){ /* implementation I using a. */ }
}
namespace {
   int  a;
   void f(){ /* implementation II using a. */ }
   int  g(){ /* implementation II using a. */ }
}

But I will use other name in one file. Or, change the name of external linkage necessary part and keep rest static.

One thing is not so beautiful in C++ is namespace, class, struct, and union are not the same. They all have a slightly different way (e.g., `;' is necessary with class, struct, union, but not namespace.) Yet nested class and struct are possible. In Java, they are the same and you do not need to remember small difference. However, I think many of them come from historical reason and performance issue.

Unnamed class and struct may more useful like lambda, I presume. In Java, you can use with abstract class. But I do not need it in C++ since it is already quite complicated and I will be happy to give one time name for this. Thanks. There is also unnamed union and it is another function.... Sigh.


How can I make a legal function which I can not call... Finding friends.

Once I saw next code when I moved gcc 4.

class A {
  ...
  friend void f(){
     access to private of A;
  }
};

gcc 3.x, you can call the function f(), like ::f(); However, gcc 4.1.0 said,

friend.cc:**: error: '::f' has not been declared

I can not call that f() if I tried several ways like

I can not. If it a bug? No, C++ book said, friend class or function must be declared in advance. So next works.
extern void f();
class A {
  ...
  friend void f(){
     access to private of A;
  }
};
// f() is not declared
class A {
  ...
  friend void f(); // useless (in 11.5.1 C++ book)
};
void f(){
  // if you did not access to inside of A, since this f() is not a
  // friend of A
}

void bar(){
  ...
  f(); 	// you can call f();
}
Now C++ magic, you can write
// f() is not declared
class A {
  ...
  friend void f() {
    // definition of f()!
  }
};
I think it is legal, but you have just made a function you can not call it at all!.

I do not know exactly the reason of this one. But I can assume this feature of C++. It may be a historical reason.

One more tip,

// f() is not declared
class A {
  ...
  friend void ::f() {	// lives in global?
    // definition of f()!
  }
};
does not work in gcc 4.1.0. But friend is declaration keyword. So, it smells dangerous to use this way. It is better to not tweak the language. ``Kunshi ayauki ni Chikayorazu. (=Der Weise begibt sich nicht in Gefahr.)


Linker


Once virtual, alywas virtual


Copyright (C) 2003-2007 YAMAUCHI Hitoshi
Most recent update : :