Можно ли скопировать класс тривиального типа, если не все его члены инициализированы?

(Я только что понял, что сначала мне нужно решить гораздо более простую проблему с копированием объединений: при копировании объекта объединения создается подобъект-член? Сначала см. Другой вопрос.)

Неявно сгенерированные операции копирования (конструктор и присваивание) класса выполняют копию члена за членом (инициализация или присваивание). (Для тривиального типа это то же самое.)

Таким образом, класс с некоторыми неинициализированными членами не может быть скопирован, поскольку доступ к неинициализированным объектам является незаконным.

struct C {
  int m1, m2;
};

void f() {
  C c1, c2;

  c1.m1 = 1;
  c2 = c1; // not initialized
}

Но объединение всегда можно скопировать, даже если оно содержит члены класса, некоторые из которых не инициализированы (потому что... по определению не инициализируются два члена объединения).

Означает ли это, что копирование объединения класса с неинициализированными членами допустимо:

union U {
  C m;
};

void g() {
  U u1, u2;
  u1.m.m1 = 1;
  u2 = u1;
}

и если да, то можно ли скопировать классы путем преобразования в такое объединение?

void f2() {
  C c1, c2;

  c1.m1 = 1;
  (U&)c2 = (U&)c1; // not initialized?
}

1 ответ

Да, вы можете скопировать объединение с неинициализированным (косвенным) членом - с помощью оператора присваивания копирования / перемещения по умолчанию, который определен для копирования представления объекта. (Вы также можете написать свой собственный оператор, который использовалstd::memcpy. Очевидно, это дефект формулировки, если оператор по умолчанию не устанавливает правильный активный элемент иstd::memcpy должен поступить так же.)

Однако вы не можете использовать преобразование в объединение в качестве более безопасной копии для обычных объектов класса; вызов оператора присваивания имеет неопределенное поведение в соответствии с необходимым специальным правилом, поскольку он не включает доступ к какому-либо (скалярному) объекту. Твой собственныйstd::memcpyна основе реализации будет нормально, даже через reinterpret_cast(!), но это не заслуживает освещения в печати - чтение / копирование неопределенных значений через unsigned char (и, возможно char) а также std::byteэто всегда разрешено).

Другие вопросы по тегам