聚合初始化在C++11中何时有效
When is aggregate initialisation valid in C++11?
假设我们有以下代码:
#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
也不是一个集合。
然而,我可以聚合初始化B。此外,这可以在不调用复制或移动构造函数的情况下完成(例如,ideone上的C++0x GCC 4.5.1)。
这种行为似乎是一种有用的优化,特别是对于将没有廉价移动的大型堆栈类型组合在一起而言。
我的问题是:在C++0x下,这种聚合初始化什么时候有效?
编辑+跟进问题:
下面的DeadMG回答如下:
这根本不是聚合初始化,而是统一初始化,在这种情况下,这基本上意味着调用构造函数,而无复制或移动可能是由RVO和NRVO完成的。
请注意,当我将B
更改为以下内容时:
struct B
{
A a;
B(const A& a_) : a(a_) {}
B(A&& a_) : a(std::move(a_)) {}
};
执行移动。
所以,如果这只是一个统一的初始化,只是调用构造函数,不做任何特殊的事情,那么我该如何编写一个允许删除移动的构造函数呢?
或者GCC只是在有效的情况下不删除移动,如果是,是否有编译器和优化设置可以删除移动?
根据新标准第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}};
对象CCD_ 7是用在适当位置执行的所有相关构造函数来构造的。任何地图、字符串或MyClasses都不会被复制或移动。请注意,底部的两个变体做的是相同的事情。如果您愿意,您甚至可以将MyClass的复制和移动构造函数设置为私有的。
这根本不是聚合初始化,而是统一初始化,在这种情况下,这基本上意味着调用构造函数,而无复制或移动可能是由RVO和NRVO完成的。
- 欧拉项目#8答案是大以获得有效答案
- 何时在引用或唯一指针上使用移动语义
- 调整大小后指向元素值的指针unordered_map有效?
- 何时提供默认参数作为模板参数
- 为什么是0;C++中的有效语句
- 最高有效数字侧的第N位
- GCC对可能有效的代码抛出init list生存期警告
- 有效地使用std::unordered_map来插入或增加键的值
- C++-明确何时以及如何调用析构函数
- c++中O(n^(1/3))中一个数的除数的有效计数
- 使用无符号字符数组有效存储内存
- 自定义先决条件对移动分配运算符有效吗
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 为什么将值返回函数传递给重载=运算符对运算符函数有效,而对其他运算符无效
- 有哪些有效的方法可以消除一组 100 万个字符串>重复数据?
- 指向派生类的指针中的"static_cast<Base*>(static_cast<void*>(派生))"何时有效?
- 何时有效使用存储桶排序以及需要多少存储桶
- 我如何有效地清理此程序并仍然检测文件输入何时不是字母
- 检查双精度何时有效为零
- 聚合初始化在C++11中何时有效