2012-07-03 2 views
3

Просто, когда я думал, что я понимаю, многоходовые двигаться КОНСТРУКЦИЯ из iostreams в C++ 11 (спасибо https://stackoverflow.com/a/8156356/273767 для интро), я столкнулся с этим:Что происходит с базой base_ostream при перемещении элемента basic_iostream?

§27.7.2.5.1 [iostream.cons ]/3

basic_iostream(basic_iostream&& rhs);

3 эффекты: Перемещение конструкций из RValue РИТ путем построения basic_istream базового класса с move(rhs).

Так что же происходит с другой базой, basic_ostream?

Я вижу LibC++ дал std::basic_ostream в protected default constructor, который называется здесь (а также, в противоречии с буквой §27.7.2.5.1/1, в нормальном constructor of basic_iostream), и ничего не делает. Так оно и должно быть?

ответ

7

Как вы отмечаете, спецификация для:

explicit basic_iostream(basic_streambuf<charT,traits>* sb); 

инициализирует обе базы. Я никогда не был в порядке с этим:

http://cplusplus.github.com/LWG/lwg-closed.html#135

как это приводит к одногоbasic_ios::init() функции, которая вызывается дважды на одном объекте виртуальной базы. Комитет постановил, что эта двойная инициализация была безвредной. Я не согласился с тем, что отказался выполнять спецификацию в отношении этой детали. Но спецификация говорит о двойном инициализации виртуального базового класса.

Когда пришло время указать конструктор перемещения basic_iostream, я был на водительском месте. И поэтому я уточнил, как я думал лучше (не дважды инициализировать basic_ios). Это решение еще предстоит оспаривать, но, вероятно, в конечном итоге.

Обратите внимание, что во избежание двойной инициализации конструктор по умолчанию basic_ostream должен быть тщательно обработан, чтобы ничего не делать. И ничем я ничего не имею в виду. Нет нулевой инициализации:

protected: 
    _LIBCPP_ALWAYS_INLINE 
    basic_ostream() {} // extension, intentially does not initialize 

К счастью, базовые классы basic_ostream фактически не указано ничего не делать в их конструкторы по умолчанию. Итак, все просто работает: basic_ostream по умолчанию строит и не касается памяти. Затем производные клиенты звонят init(basic_streambuf<char_type, traits_type>*)ровно один раз, чтобы сделать фактическую конструкцию basic_ios/ios_base.

Это действительно грязный дизайн. Отказавшись от двойной инициализации виртуальной базы, я чувствую, что libC++ делает дизайн немного менее грязным и немного более надежным. Это стандартное поведение для конструктора перемещения, а не стандартное поведение для конструктора, принимающего streambuf*.

+1

Просвещает, как всегда. – Cubbi

3

Я согласен с Говардом, что это своего рода бородавка по стандартной спецификации.

В моей реализации, я решил использовать более конкретный вызов расширения конструктора

basic_iostream(basic_iostream&& _Other) 
    : std::basic_istream<char_type, traits_type>(std::move(_Other)), 
    std::basic_ostream<char_type, traits_type>(basic_ostream::_NoInit) 
{ } 

с помощью специального protected конструктор базового класса

protected:  
    // special interface for basic_iostream 

    enum __no_init_t { _NoInit }; 

    basic_ostream(__no_init_t) 
    { } 

Чистый эффект тот же.

+0

+1 Это хорошее решение Бо. –