数组声明和初始化在C ++ 11 [英] Array declaration and initialization in C++11
问题描述
这里有8种方法可以在C ++ 11中声明和初始化数组,这在 g ++
下可以确定:
Here are 8 ways to declare and initialize arrays in C++11 that seems ok under 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}});
根据严格标准(和即将到来的C ++ 14标准),哪些是正确的?
最常见的/使用的和避免的那些(和什么原因)?
What are the correct ones according to the strict standard (and the upcoming C++14 standard) ? What are the most common/used and those to avoid (and for what reason) ?
推荐答案
C ++ 11 summary / TL; DR
C++11 summary / TL;DR
- 由于大括号缺陷,示例0,2,6不需要工作。
- 由于未指定是否
std :: array $ c,因此最新版本的编译器会执行该缺陷的建议解决方案$ c>包含一个原始数组。因此,实施例1,3,5,7不需要工作。
- 示例4将始终工作:
std :: array< int ,3> arr4 = {1,2,3};
- Due to the brace elision defect, examples 0, 2, 6 are not required to work. Recent version of compilers however implement the proposed resolution for that defect, so that these examples will work.
- As it is unspecified whether
std::array
contains a raw array. Therefore, examples 1, 3, 5, 7 are not required to work. However, I do not know of a Standard Library implementation where they do not work (in practice). - Example 4 will always work:
std::array<int, 3> arr4 = {1, 2, 3};
我希望版本4或版本2
I'd prefer version 4 or version 2 (with the brace elision fix), since they initialize directly and are required/likely to work.
对于Sutter的AAA风格,你可以使用 auto arrAAA = std :: array< int,3> {1,2,3};
,但这需要大括号修饰。
For Sutter's AAA style, you can use auto arrAAA = std::array<int, 3>{1, 2, 3};
, but this requires the brace elision fix.
std :: array
需要是一个聚合[array.overview] / 2,这意味着它没有用户提供的构造函数(即只有默认值,复制,移动ctor)。
std::array
is required to be an aggregate [array.overview]/2, this implies it has no user-provided constructors (i.e. only default, copy, move ctor).
std::array<int, 3> arr0({1, 2, 3});
std::array<int, 3> arr1({{1, 2, 3}});
使用(..)
直接初始化。这需要一个构造函数调用。在 arr0
和 arr1
的情况下,只有复制/移动构造函数可行。因此,这两个例子意味着从braced-init-list中创建一个临时 std :: array
,并将其复制/移动到目标。通过复制/移动精确,允许编译器 省略该复制/移动操作,即使它具有副作用。
An initialization with (..)
is direct-initialization. This requires a constructor call. In the case of arr0
and arr1
, only the copy/move constructor are viable. Therefore, those two examples mean create a temporary std::array
from the braced-init-list, and copy/move it to the destination. Through copy/move elision, the compiler is allowed to elide that copy/move operation, even if it has side effects.
NB即使临时值是prvalues,它可能调用一个副本(语义上,在复制之前),因为 std :: array
的移动ctor可能不被隐式声明,例如。如果已删除。
N.B. even though the temporaries are prvalues, it might invoke a copy (semantically, before copy elision) as the move ctor of std::array
might not be implicitly declared, e.g. if it were deleted.
std::array<int, 3> arr6 = std::array<int, 3>({1, 2, 3});
std::array<int, 3> arr7 = std::array<int, 3>({{1, 2, 3}});
这些是复制初始化的示例。通过braced-init-list {1,2,3}创建了两个临时表:
These are examples of copy-initialization. There are two temporaries created:
- code>通过表达式
std :: array
(..)调用复制/移动构造函数
- through the braced-init-list
{1, 2, 3}
to call the copy/move constructor - through the expression
std::array<int, 3>(..)
后面的临时文件被复制/移动到指定的目标变量。
the latter temporary then is copied/moved to the named destination variable. The creation of both temporaries can be elided.
据我所知,一个实现可以写一个(这种可能性由[container.requirements.general]排除,对David Krauss感到遗憾,见此讨论。)显式数组(array const& )= default;
构造函数和不违反标准;这将使这些例子不成立。
As far as I know, an implementation could write an (This possibility is ruled out by [container.requirements.general], kudos to David Krauss, see this discussion.)explicit array(array const&) = default;
constructor and not violate the Standard; this would make those examples ill-formed.
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}};
这是聚合初始化。它们都直接初始化 std :: array
,而不调用 std :: array
语义)创建一个临时数组。 std :: array
的成员通过复制初始化初始化(见下文)。
This is aggregate-initialization. They all "directly" initialize the std::array
, without calling a constructor of std::array
and without (semantically) creating a temporary array. The members of the std::array
are initialized via copy-initialization (see below).
关于大括号的主题:
在C ++ 11标准中,大括号只适用于 T x = {a};
但不是 T x {a};
。这是视为缺陷,将在C ++ 1y中修复,但是提议的解决方案不是标准的一部分(DRWP状态,参见链接页面的顶部),因此您不能指望您的编译器也为 T x {a};
。
In the C++11 Standard, brace elision only applies to declarations of the form T x = { a };
but not to T x { a };
. This is considered a defect and will be fixed in C++1y, however the proposed resolution is not part of the Standard (DRWP status, see top of the linked page) and therefore you cannot count on your compiler implementing it also for T x { a };
.
因此, std :: array< int,3& arr2 {1,2,3};
(示例0,2,6)严重错误。据我所知,最近的clang ++和g ++版本允许在 T x {a};
中已经有支架。
Therefore, std::array<int, 3> arr2{1, 2, 3};
(examples 0, 2, 6) are ill-formed, strictly speaking. As far as I know, recent versions of clang++ and g++ allow the brace elision in T x { a };
already.
在示例6中, std :: array
使用复制初始化:传递也是copy-init。但是,在 T x = {a};
形式的声明中,也禁止支架限制
In example 6, std::array<int, 3>({1, 2, 3})
uses copy-initialization: the initialization for argument passing is also copy-init. The defective restriction of brace elision however, "In a declaration of the form T x = { a };
", also disallows brace elision for argument passing, since it's not a declaration and certainly not of that form.
在聚合的主题上,初始化:
On the topic of aggregate-initialization:
由于 Johannes Schaub 指出在评论中,它是保证您可以使用以下语法[array.overview] / 2初始化 std :: array
:
array<T, N> a = { initializer-list };
您可以从中推导出<允许以 T x {a};
的形式,语法
You can deduce from that, if brace-elision is allowed in the form T x { a };
, that the syntax
array<T, N> a { initializer-list };
格式正确,含义相同。但是,不能保证 std :: array
实际上包含一个原始数组作为其唯一的数据成员(另见 LWG 2310 )。我认为一个例子可以是部分专门化 std :: array< T,2>
,其中有两个数据成员 T m0
和 T m1
。因此,不能得出结论:
is well-formed and has the same meaning. However, it is not guaranteed that std::array
actually contains a raw array as its only data member (also see LWG 2310). I think one example could be a partial specialization std::array<T, 2>
, where there are two data members T m0
and T m1
. Therefore, one cannot conclude that
array<T, N> a {{ initializer-list }};
格式正确。这不幸地导致的情况是,没有保证的方法初始化 std :: array
临时w / o支架elision为 T x {a};
,也意味着奇数例子(1,3,5,7)不需要工作。
is well-formed. This unfortunately leads to the situation that there's no guaranteed way of initializing a std::array
temporary w/o brace elision for T x { a };
, and also means that the odd examples (1, 3, 5, 7) are not required to work.
所有这些初始化 std :: array
的方法最终都会导致聚合初始化。它被定义为聚合成员的复制初始化。但是,使用braced-init-list的复制初始化仍然可以直接初始化聚合成员。例如:
All of these ways to initialize a std::array
eventually lead to aggregate-initialization. It is defined as copy-initialization of the aggregate members. However, copy-initialization using a braced-init-list can still directly initialize an aggregate member. For example:
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
首先尝试从initializer-clause <$>初始化数组元素c $ c> 1 和 2
。这个复制初始化相当于 foo arr0_0 = 1;
,它相当于 foo arr0_0 = foo(1); $ c $
The first tries to initialize the array elements from the initializer-clauses 1
and 2
, respectively. This copy-initialization is equivalent to foo arr0_0 = 1;
which in turn is equivalent to foo arr0_0 = foo(1);
which is illegal (deleted copy-ctor).
第二个不包含表达式列表,而是初始化器列表,因此它不能满足需求[array.overview] / 2。在实际中, std :: array
包含一个原始数组数据成员,它将从第一个初始化子句 {1} / code>,那么第二个子句
{2}
是非法的。
The second does not contain a list of expressions, but a list of initializers, therefore it doesn't fulfil the requirements of [array.overview]/2. In practice, std::array
contains a raw array data member, which would be initialized (only) from the first initializer-clause {1}
, the second clause {2}
then is illegal.
问题作为第二:如果是是数组数据成员,但是不能保证。
The third has the opposite problem as the second: It works if there is an array data member, but that isn't guaranteed.
这篇关于数组声明和初始化在C ++ 11的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!