7

unique_ptr の C++03 エミュレーションがどのように実装されているかを理解しようとしています。unique_ptr は std::auto_ptr に非常に似ていますが、より安全です。auto_ptr が所有権を暗黙的に (つまり、黙って) 譲渡した場合、コンパイラ エラーを吐き出します。たとえば、単純な割り当て。関数moveは、エミュレートされた unique_ptr の安全性の背後にある鍵です。

質問:

  1. 移動機能が 3 つあるのはなぜですか?
  2. 参照を受け取り、それを右辺値に変換する 3 番目の move 関数は、次のように実装 (簡略化) されています。

    T move(T &t) { 
      return T(detail_unique_ptr::rv<T>(t)); 
    }
    

上記のコードでは、T への明示的な変換は不必要に思えます。実際、Visual Studio 2010 は T への明示的な変換がなくても問題ありません。

T move(T &t) {
  return detail_unique_ptr::rv<T>(t);
}

ただし、g++、clang、Comeau は 2 番目のバージョンが好きではありません。unique_ptr<T>これらのコンパイラは、パラメーターとして取るコンストラクターがないと文句を言いdetail_unique_ptr::rv<T>ます。何故ですか?unique_ptr は、パラメーターとして受け取る (非明示的な) コンストラクターを既に定義してdetail_unique_ptr::rv<T>います。それが自動的に取得されないのはなぜですか?

4

1 に答える 1

3

その理由は、ユーザー定義の変換を行わずに unique_ptr を別の unique_ptr で初期化できないためです(rv への変換、rvalue を unique_ptr の rv 取得コンストラクターに渡すことによって)。unique_ptrただし、 (のように)のctorを明示的に呼び出さないunique_ptr(...)場合は、コピーの初期化を行います。この場合、最初に右辺値の一時的なunique_ptrを正常に構築しますが、その一時的なコピーを戻り値のターゲットオブジェクトにコピーできません。定義された変換が許可されます (これは、「初期化で 2 つのユーザー定義の変換を行わない」という原則規則とも呼ばれます)。Msvc では、非標準の unique_ptr 参照を取得する ctor をコピーで使用できますが、これは標準ではありません。

同じクラスのオブジェクトからクラスのコピー初期化を行う場合、そのような 2 段階の初期化はありません。ソース オブジェクトは、 の非明示的なコンストラクターに渡されるだけで、rv を取得するコンストラクターunique_ptrを使用するように変換さrvれ、その方法で戻り値のターゲット オブジェクトが正常に構築されます。

同じ理由で、 からunique_ptr<Derived>への暗黙的な変換はありませんunique_ptr<Base>。最初のステップでは、unique_ptr<Base>が正常に作成されますが、その一時をunique_ptr<Base>ターゲット オブジェクトにコピーするときに、ユーザー定義の変換を使用できないという制限により、成功が妨げられます。

于 2011-12-09T21:53:52.677 に答える