Ron's Member Idiom |
class fdoutbuf : public std::streambuf { public: explicit fdoutbuf(int fd); //... }; class fdostream : public std::ostream { protected: fdoutbuf buf; public: explicit fdostream(int fd) : buf(fd), std::ostream(&buf) { } //... };
This is undefined because C++'s initialization order mandates that the base class is initialized before the member it uses. Ron Klatchko and Dietmar Kühl developed a way around this by using the initialization order in his favor. Base classes are intialized in order of declaration, so moving the desired member to another base class, that is initialized before the desired base class, can ensure proper initialization. But note that virtual base classes are initialized before all other base classes. The solutions looks therefore as follows:
class fdoutbuf : public std::streambuf { public: explicit fdoutbuf(int fd); //... }; class fdostream : protected virtual fdoutbuf, public std::ostream { public: explicit fdostream(int fd) : fdoutbuf(fd), std::ostream(&buf) { } //... };
fdoutbuf
has to be the first base class and virtual because std::ostream
itself has a virtual base class (std::ios).
As a result, the order of initialization is as follows:
- all virtual base classes in the order of declaration
- all non-virtual base classes in the order of declaration
- all members in the order of declaration
See http://lists.boost.org/MailArchives/boost/msg10147.php for an idea of a template that supports Ron's Member Idiom.
Thanks to Dietmar Kühl and Ron Klatchko for this trick and wording.