As you point out, the spec for:
explicit basic_iostream(basic_streambuf<charT,traits>* sb);
initializes both bases. I've never been ok with that:
http://cplusplus.github.com/LWG/lwg-closed.html#135
as it causes the single basic_ios::init()
function to be called twice on the same virtual base object. The committee ruled that this double initialization was harmless. I disagreed strongly enough that I refused to implement the specification in regards to this detail. But the spec says to double initialize the virtual base class.
When it came time to specify the basic_iostream
move constructor, I was in the driver's seat. And so I specified it how I thought best (to not doubly initialize basic_ios
). That decision has yet to be challenged, but probably will be eventually.
Note that in order to avoid the double initialization, the basic_ostream
default constructor has to be carefully crafted to do absolutely nothing. And by nothing I really mean nothing. No zero initialization:
protected:
_LIBCPP_ALWAYS_INLINE
basic_ostream() {} // extension, intentially does not initialize
Fortunately the base classes of basic_ostream
are actually specified to do nothing in their default constructors. So everything just works: basic_ostream
default constructs and doesn't touch memory. Then derived clients call init(basic_streambuf<char_type, traits_type>*)
exactly once to do the actual construction of basic_ios
/ios_base
.
It's a really messy design. By refusing to double initialize the virtual base, I feel libc++ makes the design a little less messy, and a little more reliable. This is standard behavior for the move constructor, and not standard behavior for the constructor taking a streambuf*
.