我的印象是阵列不可复制(或可分配)。
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
这里发生了什么?
答案 0 :(得分:20)
默认的复制构造函数和赋值运算符分别对每个成员使用复制构造和赋值。当有一个数组时,复制构造或赋值用于数组的每个元素(这是非常明确的)。
这是规则,来自第12.8节([class.copy]
):
非联合类
X
的隐式定义的复制/移动构造函数执行其基础和成员的成员复制/移动。 [注意:忽略非静态数据成员的 brace-or-equal-initializers 。另请参见12.6.2中的示例。 - 结束注释]初始化的顺序与用户定义的构造函数中基数和成员的初始化顺序相同(见12.6.2)。设x
为其中的参数 构造函数,或者,对于移动构造函数,引用参数的xvalue。以适合其类型的方式复制/移动每个基本或非静态数据成员:
- 如果该成员是一个数组,则每个元素都使用相应的
x
子对象进行直接初始化;- 如果成员m的右值引用类型为
T&&
,则会使用static_cast<T&&>(x.m)
进行直接初始化;- 否则,基础或成员使用
x
的相应基础或成员进行直接初始化。
和
非联合类
X
的隐式定义的复制/移动赋值运算符执行其子对象的成员复制/移动分配。X
的直接基类首先按照它们在 base-specifier-list 中声明的顺序分配,然后分配X
的直接非静态数据成员。按照在课程定义中声明的顺序分配。令x
或者是函数的参数,或者对于move运算符,是指参数的xvalue。每个子对象都以适合其类型的方式分配:
- 如果子对象是类类型,就好像通过调用operator =将子对象作为对象表达式而x的对应子对象作为单个函数参数(就像通过显式限定;即忽略任何可能的更多派生类中的虚拟覆盖函数);
- 如果子对象是一个数组,则以适合元素类型的方式分配每个元素;
- 如果子对象是标量类型,则使用内置赋值运算符。
C::C(const C&)
与C::C(C&)
等之间的签名选择规则还包括引用数组元素类型的语言。
答案 1 :(得分:4)
数组既不可复制也不可赋值。但是,具有数组成员的结构已生成复制构造和复制分配。这是一项特殊规则:即他们不需要自行复制或转让。