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

Является ли класс с удаленным экземпляром copy-constructor тривиально копируемым?

Является ли этот класс:

class A {
  public:
    A() = default;
    A(const A&) = delete;
};

тривиально с возможностью копирования? (По крайней мере, кажется, что clang так думает (live))

В частности,

A a,b;
std::memcpy(&a, &b, sizeof(A));

вызывать поведение undefined?

Контекст: Этот ответ [удалено, потому что доказано неверно] плюс его дерево комментариев.

4b9b3361

Ответ 1

Обновить. Предлагаемое разрешение CWG 1734, в настоящее время в состоянии "готово", изменит [class]/p6:

Тривиально-совместимый класс - это класс:

  • где каждый конструктор копирования, конструктор перемещения, оператор присваивания копии и оператор назначения перемещения (12.8 [class.copy], 13.5.3 [over.ass]) либо удаляется, либо тривиально,
  • который имеет по крайней мере один неиспользуемый конструктор копии, перемещает конструктор, оператор присваивания копии или оператор переноса перемещения, и
  • который имеет тривиальный, не удаленный деструктор (12.4 [class.dtor]).

Это отображает такие классы, как

struct B {
    B() = default;
    B(const B&) = delete;
    B& operator=(const B&) = delete;
};

больше не копируется тривиально. (Классы такого типа включают в себя примитивы синхронизации, такие как std::atomic<T> и std::mutex.)

Однако A в OP имеет неявно объявленный, не удаленный оператор назначения копирования, который является тривиальным, поэтому он остается тривиально с возможностью копирования.

Оригинальный ответ для ситуации, предшествующей CWG1734, сохраняется ниже для справки.


Да, несколько противоречиво, он тривиально можно копировать. [Класс]/p6:

Тривиально-скопируемый класс - это класс, который:

  • не имеет нетривиальных конструкторов копирования (12.8),
  • не имеет нетривиальных конструкторов перемещения (12.8),
  • не имеет нетривиальных операторов присваивания копий (13.5.3, 12.8),
  • не имеет нетривиальных операторов присваивания перемещения (13.5.3, 12.8) и
  • имеет тривиальный деструктор (12.4).

[class.copy]/р12:

Конструктор копирования/перемещения для класса X тривиален, если он не является предоставляемый пользователем, его список параметров-параметров эквивалентен parameter-type-list неявного объявления, а если

  • класс X не имеет виртуальных функций (10.3) и виртуальных базовых классов (10.1) и
  • класс X не имеет нестатических элементов данных с нестабильным типом, а
  • конструктор, выбранный для копирования/перемещения каждого подобъекта прямого базового класса, тривиален и
  • для каждого нестатического элемента данных X, относящегося к типу класса (или его массиву), конструктор, выбранный для копирования/перемещения этого элемента, тривиальным;

Аналогично ([class.copy]/p25):

Оператор присваивания копирования/перемещения для класса X тривиален, если он не является предоставляемый пользователем, его список параметров-параметров эквивалентен parameter-type-list неявного объявления, а если

  • класс X не имеет виртуальных функций (10.3) и виртуальных базовых классов (10.1) и
  • класс X не имеет нестатических элементов данных с нестабильным типом, а
  • оператор присваивания, выбранный для копирования/перемещения каждого подобъекта прямого базового класса, тривиален и
  • для каждого нестатического элемента данных X, относящегося к типу класса (или его массиву), оператор присваивания, выбранный для копирования/перемещения этого элемента, тривиальным;

[class.dtor]/р5:

Деструктор тривиален, если он не предоставляется пользователем, и если:

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

[dcl.fct.def.default]/р5:

Функция предоставляется пользователю, если она объявлена ​​пользователем и не явно по умолчанию или удалено в его первом объявлении.

В самом деле, это был источник проблем для самого комитета, потому что в соответствии с текущим определением atomic<T> (наряду с мьютексами и условием переменные) будет тривиально скопируемым. (И, очевидно, разрешить кому-то memcpy через atomic или mutex без вызова UB было бы... просто сказать серьезно проблематично.) См. Также N4460.