10

次のコードがあるとしましょう。

#include <iostream>
#include <string>

struct A
{
  A() {}
  A(const A&) { std::cout << "Copy" << std::endl; }
  A(A&&) { std::cout << "Move" << std::endl; }
  std::string s;
};

struct B
{
  A a;
};

int main()
{
  B{A()};
}

ここで、構造体にAは自明ではないコンストラクターと、集合体ではないと思われるstd::stringメンバーの両方があるため、構造体は集合体ではないと思います。これはおそらくB、 も集合体ではないことを意味します。

それでも、initialize B を集約できます。さらに、これは、copy コンストラクターも move コンストラクターも呼び出されずに実行できます (例: C++0x GCC 4.5.1 on ideone )。

この動作は、特に安価な動きを持たない大きなスタック タイプを一緒に構成する場合に、便利な最適化のように思えます。

私の質問は、C++0x でこの種の集計初期化が有効になるのはいつですか?

編集 + フォローアップの質問:

以下のDeadMGは次のように答えました:

これは集合体の初期化ではなく、均一な初期化です。これは基本的に、この場合はコンストラクターを呼び出すことを意味し、コピーや移動はおそらく RVO と NRVO によって行われます。

B次のように変更すると、次のことに注意してください。

struct B
{
  A a;
  B(const A& a_) : a(a_) {}
  B(A&& a_) : a(std::move(a_)) {}
};

移動が実行されます。

したがって、これが単なる均一な初期化であり、コンストラクターを呼び出すだけで特別なことを何もしない場合、移動を省略できるコンストラクターをどのように作成すればよいでしょうか?

それとも、GCC は、有効な場合にここで移動を省略していないだけですか? もしそうなら、移動を省略できるコンパイラと最適化の設定はありますか?

4

2 に答える 2

6

新しい標準である8.5.1節(Aggretates)によると、十分に単純な型(たとえば、ユーザー定義のコンストラクターがない)は、集合体としての資格があります。このような集合体Fooの場合、書き込みFoo x{a, b, ... };はリスト項目からメンバーを構築します。

簡単な例:

struct A
{
  std::unordered_map<int, int> a;
  std::string b;
  std::array<int,4> c;
  MyClass d; // Only constructor is MyClass(int, int)
};

// Usage:
 A x{{{1,-1}, {12, -2}}, "meow", {1,2,3,4}, MyClass(4,4)};
// Alternative:
 A x{{{1,-1}, {12, -2}}, "meow", {1,2,3,4}, {4,4}};

オブジェクトxは、関連するすべてのコンストラクターが実行された状態で構築されます。マップ、文字列、またはMyClassesがコピーされたり移動されたりすることはありません。下部にある両方のバリアントが同じことを行うことに注意してください。必要に応じて、MyClassのコピーおよび移動コンストラクターをプライベートにすることもできます。

于 2011-06-08T02:44:05.620 に答える
2

これは集合体の初期化ではなく、均一な初期化です。この場合、基本的にはコンストラクターを呼び出すことを意味し、コピーや移動はおそらく RVO と NRVO によって行われます。

于 2011-06-08T02:00:13.300 に答える