C ++ 11での「return {}」ステートメントの意味


115

ステートメントは何ですか

return {};

C ++ 11では、(たとえば)の代わりにそれをいつ使用するかを示します

return NULL;

または

return nullptr;

59
関数の戻り値の型のデフォルトで構成されたインスタンスを返します。
Richard Hodges

またはそれはreturn;価値がなく単純ですか?
i486

いいえ、議論が明らかにするように、関数が何かを返す必要がある場合(つまり、戻り値の型がvoidではない場合)はコンパイル時のエラーです。return; 一方return{};、戻り値の型がある場合は有効です。
Pedia 2016

@Pedia常にではありませんが、一部のオブジェクトでは構築に引数が必要になります
MM

回答:


108

return {};「空のリスト初期化子で初期化された関数の戻り値型のオブジェクトを返す」ことを示します。正確な動作は、返されたオブジェクトのタイプによって異なります。

cppreference.comから(OPにはC ++ 11のタグが付けられているため、C ++ 14およびC ++ 17のルールを除外しました。詳細については、リンクを参照してください):

  • braced-init-listが空で、Tがデフォルトのコンストラクターを持つクラス型である場合、値の初期化が実行されます。
  • それ以外の場合、Tが集約型の場合、集約の初期化が実行されます。
  • それ以外の場合、Tがstd :: initializer_listの特殊化である場合、Tオブジェクトは、コンテキストに応じて、braced-init-listから直接初期化またはコピー初期化されます。
  • そうでない場合は、Tのコンストラクターが2つのフェーズで考慮されます。

    • std :: initializer_listを唯一の引数として、または残りの引数にデフォルト値がある場合は最初の引数として取るすべてのコンストラクターが検査され、オーバーロード解決によって型std :: initializer_listの単一の引数と照合されます
    • 前のステージで一致が生成されない場合、Tのすべてのコンストラクターは、braced-init-listの要素で構成される引数のセットに対するオーバーロードの解決に参加します。ただし、狭くない変換のみが許可されます。この段階で、コピーリストの初期化に最適な一致として明示的なコンストラクターが生成される場合、コンパイルは失敗します(単純なコピーの初期化では、明示的なコンストラクターはまったく考慮されません)。
  • それ以外の場合(Tがクラス型ではない場合)、braced-init-listに要素が1つしかなく、Tが参照型ではないか、または要素の型と互換性のある参照型である場合、Tは直接初期化(直接リスト初期化)またはコピー初期化(コピーリスト初期化)、ただし、ナロー変換は許可されません。

  • それ以外の場合、Tが要素の型と互換性のない参照型である場合。(参照が非const左辺値参照の場合、これは失敗します)
  • それ以外の場合、braced-init-listに要素がない場合、Tは値で初期化されます。

C ++ 11以前はstd::string、を返す関数の場合、次のように記述していました。

std::string get_string() {
    return std::string();
}

C ++ 11で中かっこ構文を使用すると、型を繰り返す必要はありません。

std::string get_string() {
    return {}; // an empty string is returned
}

return NULLそしてreturn nullptr関数はポインタ型を返すときに使用されるべきです。

any_type* get_pointer() {
    return nullptr;
}

ただし、NULLC ++ 11以降は非推奨です。これは整数値(0)の単なるエイリアスでnullptrあり、実際のポインタ型だからです。

int get_int() {
    return NULL; // will compile, NULL is an integer
}

int get_int() {
    return nullptr; // error: nullptr is not an integer
}

91

これはおそらく混乱しています:

int foo()
{
  return {};   // honestly, just return 0 - it's clearer
}

これはおそらくありません:

SomeObjectWithADefaultConstructor foo()
{
  return {};
  // equivalent to return SomeObjectWithADefaultConstructor {};
}

9
したがって、戻り値の型にデフォルトのコンストラクタがない場合は、コンパイルエラーになります。
Pedia 2016

10
戻り値の型が明示的なデフォルトコンストラクターを持たず、集計ではないクラスである場合、これはコンパイルエラーです。
オクタリスト2016

3
型にinitializer_listコンストラクターがある場合、デフォルトのコンストラクターが使用できない場合はそれが使用されませんか?
celtschk 2016

4
「おそらく混乱する」?名前のない魂が「C ++であるあの肥大したわいせつ」に言及したのはこれが理由ですか?これが提供するキーストロークの節約は、それが提供する明確さの欠如の可能性を正当化する可能性がありますか?これは誠実な質問です。実用的な例を教えてください。
MickeyfAgain_BeforeExitOfSO 2016

4
return {}次と同等ではないreturn SomeObjectWithADefaultConstructor{};
MM

26

return {};これ{}は、戻り値の初期化子であることを意味します。戻り値は空の​​リストでリスト初期化されます。


C ++標準の[stmt.return]に基づく戻り値の背景を次に示します

値で戻る関数(つまり、戻り値の型が参照ではなくvoid)の場合、戻り値と呼ばれる一時オブジェクトがあります。このオブジェクトはreturnステートメントによって作成され、その初期化子はreturnステートメントの内容によって異なります。

戻り値は、関数を呼び出したコードの完全式が終了するまで存続します。クラス型の場合は、呼び出し側が直接参照をバインドすることによって寿命が延長されない限り、デストラクタが実行されます。

戻り値は、2つの異なる方法で初期化できます。


T関数の戻り値の型であると仮定すると、次の点とreturn T{};は異なることに注意してください。return {}前者では、一時変数T{}が作成され、戻り値はその一時変数からコピー初期化されます。

Tアクセス可能なコピー/移動return {};コンストラクタがない場合、これはコンパイルに失敗しますが、これらのコンストラクタが存在しない場合でも成功します。したがって、return T{};これはコピー省略コンテキストであるため、コピーコンストラクタなどの副作用を示す可能性があります。


以下は、C ++ 14(N4140 [dcl.init.list] / 3)でのリスト初期化の簡単な要約です。ここで、初期化子は空のリストです。

  • 場合T集合体で、各部材は、その初期化されブレース-OR-等しい初期それが1つを持っていたならば、そうでない場合によってかのように{} (そう再帰的手順を適用します)。
  • 場合はT、ユーザーが提供するデフォルトコンストラクタを持つクラス型で、そのコンストラクタが呼び出されます。
  • Tが暗黙的に定義されたクラス型、または= defaultデフォルトのコンストラクタを持つクラス型の場合、オブジェクトはゼロで初期化され、デフォルトのコンストラクタが呼び出されます。
  • 場合Tstd::initializer_list、戻り値は空のようなリストがあります。
  • それ以外の場合(つまりT、クラス型ではない-戻り値の型を配列にすることはできません)、戻り値はゼロで初期化されます。

集約initが最初に来て{}、すべてのメンバーをで再帰的に初期化します。これはvalue-initである場合とそうでない場合があります。
TC

@TC正解、cppreferenceを使用しましたが、「C ++ 14まで」を見落としました
MM

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.