FAQ 22.08 How should initializers be ordered in a constructor's initialization list?Immediate base classes (left to right), then member objects (top to bottom). In other words, the order of the initialization list should mimic the order in which initializations take place. This guideline discourages a particularly subtle class of order dependency errors by giving an obvious, visual clue. For example, the following contains a hideous error. #include <iostream> using namespace std; class Y { public: Y() throw(); void f() throw(); }; Y::Y() throw() { cout << "Y ctor\n"; } void Y::f() throw() { cout << "Y used\n"; } class X { public: X(Y& y) throw(); }; X::X(Y& y) throw() { y.f(); } class Z { public: Z() throw(); protected: X x_; Y y_; }; Z::Z() throw() : y_() , x_(y_) <-- 1 { } int main() { Z z; }
The output of this program follows. Y used Y ctor Note that y_ is used (Y::f()) before it is initialized (Y::Y()). If the guideline espoused by this FAQ was employed, the error would be more obvious: the initialization list of Z::Z() would have read x_(y_), y_(), visually indicating that y_ was being used before being initialized. Not all compilers issue diagnostic messages for these cases. |