Подтвердить что ты не робот

Я думал, что массив не копируется

У меня создалось впечатление, что массив не копируется (или присваивается).

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

Что здесь происходит?

4b9b3361

Ответ 1

По умолчанию конструктор копирования и оператор присваивания используют построение копирования и назначение отдельно для каждого члена. Когда имеется массив, построение копирования или присваивание используются для каждого элемента массива (который довольно четко определен).

Здесь правило, из раздела 12.8 ([class.copy]):

Неявно определенный конструктор copy/move для неединичного класса X выполняет поэтапную копирование/перемещение своих баз и элементов. [Примечание: скопированные или равные инициализаторы нестатических членов данных игнорируются. См. Также пример в 12.6.2. - end note] Порядок инициализации совпадает с порядком инициализации баз и членов в определяемом пользователем конструкторе (см. 12.6.2). Пусть X - либо параметр конструктор или, для конструктора перемещения, значение x, относящееся к параметру. Каждый базовый или нестатический элемент данных копируется/перемещается в соответствии с его типом:

  • , если элемент является массивом, каждый элемент инициализируется напрямую с соответствующим подобъектом X;
  • если элемент m имеет ссылочный тип rvalue T&&, он инициализируется с помощью static_cast<T&&>(x.m);
  • в противном случае база или элемент инициализируются с прямой базой или элементом X.

и

Неявно определенный оператор присваивания копирования/перемещения для неединичного класса X выполняет поэтапное копирование/перемещение назначения своих подобъектов. Прямые базовые классы X назначаются первыми в порядке их объявления в списке-спецификаторе-базовом, а затем присваиваются непосредственные нестатические элементы данных X в том порядке, в котором они были объявлены в определении класса. Пусть X - либо параметр функции, либо оператор перемещения - значение x, относящееся к параметру. Каждый подобъект присваивается в соответствии с его типом:

  • если подобъект имеет тип класса, как если бы вызывал оператор = с подобъектом как выражение объекта и соответствующий подобъект x как один аргумент функции (как если бы он был явно квалифицирован, т.е. игнорировал любые возможные виртуальные функции переопределения в более производных классах);
  • , если подобъектом является массив, каждый элемент назначается в соответствии с типом элемента;
  • Если подобъект имеет скалярный тип, используется встроенный оператор присваивания.

Правило выбора подписи между C::C(const C&) vs C::C(C&) et al также включает язык, относящийся к типу элемента массива.

Ответ 2

Массивы не подлежат копированию и присваиванию. Однако структура с элементами массива создала конструкцию копирования и назначение копии. Это специальное правило: т.е. Им не нужно копировать или присваивать себя.