Когда инициализация агрегата действительна в C ++ 11? - PullRequest
10 голосов
/ 08 июня 2011

Допустим, у нас есть следующий код:

#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()};
}

Здесь я считаю, что struct A не является агрегатом, поскольку в ней есть как нетривиальные конструкторы, так и член std::string, который япрезумпция не является совокупностью.Предположительно это означает, что B также не является агрегатом.

Тем не менее, я могу агрегировать инициализацию B. Кроме того, это можно сделать без вызова конструктора копирования или перемещения (например, C ++ 0x GCC 4.5.1 на 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 просто не исключает перемещение здесь, когда это допустимо, и если да, есть ли параметр компилятора и оптимизации, который исключит перемещение?

Ответы [ 2 ]

6 голосов
/ 08 июня 2011

В соответствии с новым стандартом, п. 8.5.1 (Совокупность), достаточно простой тип (например, без пользовательских конструкторов) квалифицируется как агрегат . Для такой совокупности 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 и переместить конструкторы приватными, если хотите.

2 голосов
/ 08 июня 2011

Это вовсе не агрегатная инициализация, это равномерная инициализация, которая в основном в данном случае означает вызов конструктора, и, скорее всего, нет копирования или перемещения с помощью RVO и NRVO.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...