6

次のプログラムを検討してください。

#include<iostream>
using namespace std;

struct S
{
    S() = default;
    S(const S& other) = delete;
    S(S&& other) = delete;
    int i;
};

S nakedBrace()
{
     return {}; // no S constructed here?
}

S typedBrace()
{
     return S{};
}

int main()
{
    // produce an observable effect.
    cout << nakedBrace().i << endl; // ok
    cout << typedBrace().i << endl; // error: deleted move ctor
}

サンプル セッション:

$ g++ -Wall -std=c++14 -o no-copy-ctor no-copy-ctor.cpp
no-copy-ctor.cpp: In function 'S typedBrace()':
no-copy-ctor.cpp:19:12: error: use of deleted function 'S::S(S&&)'
   return S{};
            ^
no-copy-ctor.cpp:8:5: note: declared here
     S(S&& other) = delete;

gcc が を受け入れることに驚きましたnakedBrace()。概念的には、2 つの関数は同等であると考えました。一時的な関数がS構築されて返されます。コピー省略は実行される場合と実行されない場合がありますが、標準 (12.8/32) で義務付けられているように、move または copy ctor (両方ともここで削除されます) は引き続きアクセス可能でなければなりません。

nakedBrace()それは決して S を構築しないということですか? それとも、コピーの移動/ctorが概念的に必要ないように、ブレースの初期化を使用して戻り値に直接入力しますか?

4

2 に答える 2

1

[stmt.return]/2 ...非 void 型の式を含む return ステートメントは、値を返す関数でのみ使用できます。式の値が関数の呼び出し元に返されます。式の値は、それが現れる関数の戻り値の型に暗黙的に変換されます。return ステートメントには、一時オブジェクトの構築とコピーまたは移動が含まれる場合があります (12.2 ) ... .4) 指定された初期化子リストから。

[class.temporary]/1クラス タイプのテンポラリは、さまざまなコンテキストで作成されます: ... prvalue を返す (6.6.3) ...

そうです、私が知る限り、セマンティックの違いがあります。type の prvalue を生成するtypedBraceexpression を評価し、その式から戻り値をコピー構築しようとします。代わりに、波括弧初期化リストから直接戻り値を構築します。S{}SnakedBrace

S s{};これは、 (動作する) 対S s = S{};(動作しない)と同じ状況ですが、間接的なレベルによって多少あいまいになっています。

于 2016-01-27T15:44:17.227 に答える