我认为数组是不可复制的

Posted

技术标签:

【中文标题】我认为数组是不可复制的【英文标题】:I thought array was non copyable 【发布时间】:2012-02-28 08:23:18 【问题描述】:

我的印象是数组不可复制(或可分配)。

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

这是怎么回事?

【问题讨论】:

POD 似乎扩展到数组。否则如何“按位复制”? 相关问题Why declare a struct that only contains an array another related question 【参考方案1】:

默认的复制构造函数和赋值运算符对每个成员单独使用复制构造和赋值。当有数组时,对数组的每个元素使用复制构造或赋值(这是非常明确的)。

这是第 12.8 节 ([class.copy]) 中的规则:

非联合类X 的隐式定义复制/移动构造函数执行其基类和成员的成员复制/移动。 [ 注意:brace-or-equal-initializers 的非静态数据成员被忽略。另见 12.6.2 中的示例。 — end note ] 初始化的顺序与用户定义的构造函数中基类和成员的初始化顺序相同(参见 12.6.2)。让x 成为 构造函数,或者,对于移动构造函数,引用参数的 xvalue。每个基本或非静态数据成员都以适合其类型的方式复制/移动:

如果成员为数组,则每个元素直接用x的对应子对象初始化; 如果成员m有右值引用类型T&amp;&amp;,则直接用static_cast&lt;T&amp;&amp;&gt;(x.m)初始化; 否则,基址或成员将直接使用x 的相应基址或成员进行初始化。

非联合类X 的隐式定义复制/移动赋值运算符执行其子对象的成员复制/移动赋值。 X 的直接基类首先分配,按照它们在 base-specifier-list 中的声明顺序,然后分配 X 的直接非静态数据成员,在它们在类定义中的声明顺序。让x 是函数的参数,或者对于移动运算符,是一个引用参数的xvalue。每个子对象都以适合其类型的方式分配:

如果子对象是类类型,就好像通过调用 operator= 将子对象作为对象表达式并将 x 的相应子对象作为单个函数参数(好像通过显式限定;也就是说,忽略任何可能的更多派生类中的虚拟覆盖函数); 如果子对象是一个数组,则以适合元素类型的方式分配每个元素; 如果子对象是标量类型,则使用内置赋值运算符。

C::C(const C&amp;)C::C(C&amp;) 等之间的签名选择规则还包括引用数组元素类型的语言。

【讨论】:

那么我们可以编写自己的复制构造函数并轻松地做同样的事情吗? @Loki:我认为使用 C++11 统一初始化语法应该是可能的,例如C::C(const C&amp; x) : member_arrayx.member_array 。因为数组是一个聚合,所以应用聚合直接初始化语法。 @LokiAstari:我在 C++03(在 MSVC9 中)中做过。 X::X(const X&amp; rhs) : x(rhs.x) 适用于数组。我认为这是一方面或另一方面的疏忽。 IDEOne accepts it too @MooingDuck:在关闭语言扩展的情况下他们接受吗? Comeau 拒绝了,说数组只能用空括号初始化。 @BenVoigt:好电话。关闭语言扩展后,MSVC9 说“错误 C2536:'X::X::x':无法为数组指定显式初始化程序”【参考方案2】:

数组既不可复制也不可赋值。但是,具有数组成员的结构会生成复制构造和复制分配。这是一条特殊规则:即它们本身不需要是可复制或可分配的。

【讨论】:

以上是关于我认为数组是不可复制的的主要内容,如果未能解决你的问题,请参考以下文章

子数组是不是保证线性分配? [复制]

RFID为啥不可复制

使用数组或 List<> 哪个更好? [复制]

如何找到数组列表的长度? [复制]

C ++ 11分段错误试图将数组(<算法>)动态复制到向量中

C: unsigned char * bytes 数组将元素复制到其他 unsigned char * 数组