3

C++ 11 での iostream のマルチパス ムーブ構造を理解していると思ったとき ( https://stackoverflow.com/a/8156356/273767のイントロに感謝)、次のような問題に遭遇しました。

§27.7.2.5.1[iostream.cons]/3

basic_iostream(basic_iostream&& rhs);

3basic_istream効果: で基本クラスを構築することにより、右辺値 rhs から構造を移動しmove(rhs)ます。

では、もう一方のベースはどうなりbasic_ostreamますか?

libc++ がここで呼び出される保護されたデフォルトのコンストラクターを提供したことがわかりstd::basic_ostreamます(また、basic_iostream の通常のコンストラクターで、§27.7.2.5.1/1 の文字と矛盾して)、何もしません。それが本来あるべき姿ですか?

4

2 に答える 2

7

ご指摘のとおり、次の仕様は次のとおりです。

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

両方のベースを初期化します。私はそれで大丈夫だったことがありません:

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

同じ仮想ベースオブジェクトで単一の関数が2回呼び出されるためです。 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>*) に1回だけ呼び出します。basic_iosios_base

それは本当に厄介なデザインです。仮想ベースを二重に初期化することを拒否することで、libc ++によって設計が少し面倒でなくなり、信頼性が少し向上したと思います。これは、moveコンストラクターの標準的な動作であり、。を取るコンストラクターの標準的な動作ではありませんstreambuf*

于 2012-07-03T15:47:58.517 に答える
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)
    { }

正味の効果は同じです。

于 2012-07-03T16:26:27.330 に答える