Vin*_*ent 11 c++ initialization c++11 stdarray c++14
以下是在C++ 11中声明和初始化数组的8种方法g++:
/*0*/ std::array<int, 3> arr0({1, 2, 3});
/*1*/ std::array<int, 3> arr1({{1, 2, 3}});
/*2*/ std::array<int, 3> arr2{1, 2, 3};
/*3*/ std::array<int, 3> arr3{{1, 2, 3}};
/*4*/ std::array<int, 3> arr4 = {1, 2, 3};
/*5*/ std::array<int, 3> arr5 = {{1, 2, 3}};
/*6*/ std::array<int, 3> arr6 = std::array<int, 3>({1, 2, 3});
/*7*/ std::array<int, 3> arr7 = std::array<int, 3>({{1, 2, 3}});
Run Code Online (Sandbox Code Playgroud)
根据严格标准(以及即将推出的C++ 14标准),正确的是什么?什么是最常见的/使用的和那些要避免的(以及为什么)?
dyp*_*dyp 19
C++ 11 summary/TL; DR
std::array包含原始数组.因此,不需要实施例1,3,5,7.但是,我不知道标准库实现它们不起作用(实际上).std::array<int, 3> arr4 = {1, 2, 3};我更喜欢版本4或版本2(使用大括号省略),因为它们直接初始化并且需要/可能有效.
对于Sutter的AAA风格,你可以使用auto arrAAA = std::array<int, 3>{1, 2, 3};,但这需要支撑elision修复.
std::array 需要是一个聚合[array.overview]/2,这意味着它没有用户提供的构造函数(即只有默认,复制,移动ctor).
std::array<int, 3> arr0({1, 2, 3});
std::array<int, 3> arr1({{1, 2, 3}});
Run Code Online (Sandbox Code Playgroud)
初始化(..)是直接初始化.这需要构造函数调用.在的情况下,arr0和arr1,只有复制/移动的构造是可行的.因此,这两个示例意味着从braced-init-list 创建临时std::array,并将其复制/移动到目标.通过复制/移动省略,允许编译器忽略该复制/移动操作,即使它有副作用.
注意,即使临时值是prvalues,它也可能会调用副本(在语义上,在复制省略之前),因为std::array可能不会隐式声明移动ctor ,例如,如果它被删除.
std::array<int, 3> arr6 = std::array<int, 3>({1, 2, 3});
std::array<int, 3> arr7 = std::array<int, 3>({{1, 2, 3}});
Run Code Online (Sandbox Code Playgroud)
这些是复制初始化的示例.有两个临时创建:
{1, 2, 3}调用复制/移动构造函数std::array<int, 3>(..)然后将临时的临时复制/移动到指定的目标变量.两个临时工的创造都可以省略.
据我所知,一个实现可以写一个([container.requirements.general]排除了这种可能性,对David Krauss表示赞赏,请参阅此讨论.)explicit array(array const&) = default;构造函数,而不是违反标准; 这会使这些例子形成不良.
std::array<int, 3> arr2{1, 2, 3};
std::array<int, 3> arr3{{1, 2, 3}};
std::array<int, 3> arr4 = {1, 2, 3};
std::array<int, 3> arr5 = {{1, 2, 3}};
Run Code Online (Sandbox Code Playgroud)
这是聚合初始化.它们都"直接"初始化std::array,而无需调用构造函数(std::array无论是否)(语义上)创建临时数组.的成员std::array通过复制初始化初始化(见下文).
关于大括号的主题:
在C++ 11标准中,大括号仅适用于表单的声明T x = { a };但不适用于T x { a };.这被认为是一个缺陷,将在C++ 1y中修复,但是建议的分辨率不是标准的一部分(DRWP状态,请参见链接页面的顶部),因此您也不能指望您的编译器实现它T x { a };.
因此,std::array<int, 3> arr2{1, 2, 3};严格来说,(实例0,2,6)是不正确的.据我所知,最新版本的clang ++和g ++ T x { a };已经允许使用大括号.
在示例6中,std::array<int, 3>({1, 2, 3})使用复制初始化:参数传递的初始化也是copy-init.但是,对于括号中的缺陷限制,"在形式的声明中T x = { a };",也不允许使用括号来进行论证传递,因为它不是声明,当然也不是那种形式.
关于聚合初始化的主题:
由于约翰内斯绍布指出的评论,它只能保证你可以初始化std::array以下语法[array.overview/2:
array<T, N> a = { initializer-list };
您可以从中推断,如果表单中允许使用大括号T x { a };,则表示语法
array<T, N> a { initializer-list };
形式良好,具有相同的含义.但是,不能保证std::array实际上包含一个原始数组作为其唯一的数据成员(另见LWG 2310).我认为一个例子可能是部分专业化std::array<T, 2>,其中有两个数据成员T m0和T m1.因此,人们无法得出结论
array<T, N> a {{ initializer-list }};
结构良好.不幸的是,这导致无法保证初始化std::array临时w/o括号省略的情况T x { a };,并且还意味着奇数示例(1,3,5,7)不需要工作.
所有这些初始化的方法std::array最终都会导致聚合初始化.它被定义为聚合成员的复制初始化.但是,使用braced-init-list进行复制初始化仍然可以直接初始化聚合成员.例如:
struct foo { foo(int); foo(foo const&)=delete; };
std::array<foo, 2> arr0 = {1, 2}; // error: deleted copy-ctor
std::array<foo, 2> arr1 = {{1}, {2}}; // error/ill-formed, cannot initialize a
// possible member array from {1}
// (and too many initializers)
std::array<foo, 2> arr2 = {{{1}, {2}}}; // not guaranteed to work
Run Code Online (Sandbox Code Playgroud)
第一个尝试分别从初始化子句1和子句初始化数组元素2.这种复制初始化相当于foo arr0_0 = 1;其相当于foo arr0_0 = foo(1);非法(删除的复制器).
第二个不包含表达式列表,而是一个初始化器列表,因此它不满足[array.overview]/2的要求.实际上,std::array包含一个原始数组数据成员,它将从第一个初始化子句初始化(仅){1},{2}然后第二个子句是非法的.
第三具有相反的问题,因为第二:它的工作原理,如果有是一个数组数据成员,但是没有保证.
| 归档时间: |
|
| 查看次数: |
5394 次 |
| 最近记录: |