13

std::unique_ptr classメンバーを呼び出し元に戻そうとしています(所有権を移動しようとしています)。以下は、サンプル コード スニペットです。

class A {
public:
  A() : p {new int{10}} {}

  static std::unique_ptr<int> Foo(A &a) {
    return a.p; // ERROR: Copy constructor getting invoked
                // return std::move(a.p); WORKS FINE
  }

  std::unique_ptr<int> p;
};

この場合、コンパイラ (gcc-5.2.1) は戻り値の最適化 (コピー省略) を行うことができると思いましたstd::move()。しかし、そうではありません。なぜだめですか?

次のコードは正常に動作しているように見えますが、これは同等のようです。

std::unique_ptr<int> foo() {
  std::unique_ptr<int> p {new int{10}};
  return p;
}
4

2 に答える 2

11

[class.copy]のルールは次のとおりです。

[...]ステートメント内のが、最も内側の関数またはlambda-expressionの本体またはparameter-declaration-clauseで宣言された自動ストレージ期間を持つオブジェクトを指定returnする (おそらく括弧で囲まれた) id-expressionである場合、オーバーロードの解決オブジェクトが右辺値によって指定されたかのように、コピーのコンストラクターを選択することが最初に実行されます。

この例では:

std::unique_ptr<int> foo() {
  std::unique_ptr<int> p {new int{10}};
  return p;
}

p関数の本体で宣言された自動保存期間を持つオブジェクトの名前です。そのため、戻り値にコピーするのではなく、最初に移動しようとします。それはうまくいきます。

しかし、この例では:

static std::unique_ptr<int> Foo(A &a) {
    return a.p;
}

それは当てはまりません。 a.pはまったくオブジェクトの名前ではないので、あたかも右辺値であるかのようにオーバーロードの解決を試みません。代わりに、通常のことを行います。これは失敗するため、明示的に行う必要がありますmove()


それがルールの文言ですが、あなたの質問には答えないかもしれません. なぜこれがルールなのですか?基本的に - 私たちは安全を確保しようとしています。ローカル変数に名前を付ける場合、return ステートメントでそこから移動しても常に安全です。二度とアクセスされることはありません。最適化は簡単で、マイナス面はありません。しかし、元の例でaは、 はこの関数によって所有されておらず、 も所有されていませんa.p。そこから移動することは本質的に安全ではないため、言語は自動的に移動しようとしません。

于 2016-09-30T23:16:47.990 に答える