C++ 我认为数组是不可复制的
我的印象是数组是不可复制的(或可分配的) 但是当我把一个数组放在一个类中时,复制构造函数和赋值操作符就起作用了(我会说这是预期的,但不是我预期的)C++ 我认为数组是不可复制的,c++,arrays,copy-constructor,assignment-operator,C++,Arrays,Copy Constructor,Assignment Operator,我的印象是数组是不可复制的(或可分配的) 但是当我把一个数组放在一个类中时,复制构造函数和赋值操作符就起作用了(我会说这是预期的,但不是我预期的) 这里发生了什么?默认的复制构造函数和赋值运算符在每个成员上分别使用复制构造和赋值。当有一个数组时,在数组的每个元素上使用复制构造或赋值(定义得很好) 以下是第12.8节的规则([class.copy]): 非联合类X的隐式定义的复制/移动构造函数执行其基和成员的成员级复制/移动。[注:忽略非静态数据成员的大括号或等效初始值设定项。另请参见12.6.2
这里发生了什么?默认的复制构造函数和赋值运算符在每个成员上分别使用复制构造和赋值。当有一个数组时,在数组的每个元素上使用复制构造或赋值(定义得很好) 以下是第12.8节的规则(
[class.copy]
):
非联合类X
的隐式定义的复制/移动构造函数执行其基和成员的成员级复制/移动。[注:忽略非静态数据成员的大括号或等效初始值设定项。另请参见12.6.2中的示例。-结束注]初始化顺序与用户定义构造函数中基和成员的初始化顺序相同(请参见12.6.2)。设x
为
构造函数,或者对于move构造函数,是指参数的xvalue。以适合其类型的方式复制/移动每个基本或非静态数据成员:
- 如果成员是数组,则每个元素直接初始化为
的相应子对象李>x
- 如果成员m具有右值引用类型
,则直接使用T&
初始化它李>static_cast(x.m)
- 否则,将使用
的相应基或成员直接初始化基或成员x
X
的隐式定义的复制/移动赋值运算符执行其子对象的成员复制/移动赋值。首先按照基本说明符列表中声明的顺序分配X
的直接基类,然后按照类定义中声明的顺序分配X
的直接非静态数据成员。让x
作为函数的参数,或者对于move操作符,作为引用参数的x值。每个子对象都以适合其类型的方式指定:
- 如果子对象是类类型的,就像通过调用operator=将子对象作为对象表达式,并将对应的x子对象作为单个函数参数(就像通过显式限定;即忽略更多派生类中任何可能的虚拟重写函数)李>
- 如果子对象是一个数组,则以适合元素类型的方式指定每个元素李>
- 如果子对象是标量类型,则使用内置赋值运算符
在
C::C(const C&)
vsC::C(C&)
等之间选择签名的规则还包括引用数组元素类型的语言。数组既不可复制也不可分配。但是,具有数组成员的结构已生成副本构造和副本分配。这是一条特殊的规则:即它们本身不需要可复制或可分配。POD似乎扩展到了数组。否则“按位复制”怎么办?相关问题那么我们可以编写自己的复制构造函数并轻松地做同样的事情吗?@Loki:我认为使用C++11统一的初始化语法应该是可能的,例如C::C(const C&x):member_array{x.member_array}{}
。因为数组是聚合,所以聚合直接初始化语法适用。@LokiAstari:我在C++03(MSVC9)中使用过X::X(constx&rhs):X(rhs.X){}
适用于数组。我认为这是一个疏忽@MooingDuck:他们在关闭语言扩展的情况下接受它吗?Comeau拒绝了这一点,说数组只能用空括号初始化。@BenVoigt:很好。关闭语言扩展时,MSVC9显示“错误C2536:'X::X::X':无法为数组指定显式初始值设定项”
int x[5] = {1,2,3,4,5};
int y[5] = {6,7,8,9,0};
x = y; // Fails to compile
#include <iostream>
struct X
{
virtual ~X(){} // Just in case it was something to do with POD
// make sure its not a POD
int x[5];
};
int main()
{
X a;
a.x[0] = 0;
a.x[1] = 1;
a.x[2] = 2;
a.x[3] = 3;
a.x[4] = 4;
// Make a copy of a and test it
X b(a);
std::cout << a.x[0] << " : " << b.x[0] << "\n";
b.x[0] = 10;
b.x[1] = 11;
b.x[2] = 12;
b.x[3] = 13;
b.x[4] = 14;
// Now that we have modified 'b' make sure it is unique.
std::cout << a.x[0] << " : " << b.x[0] << "\n";
// Use assignment and see if it worked.
b = a;
std::cout << a.x[0] << " : " << b.x[0] << "\n";
}
> g++ t.cpp
> ./a.out
0 : 0
0 : 10
0 : 0