Почему класс легко копируется со всеми закрытыми специальными функциями-членами?

Код такой:

#include <iostream>
#include <type_traits>

class A
{
    A() = default;
    A(const A&) = default;
    A(A&&) = default;
    A& operator=(const A&) = default;
    A& operator=(A&&) = default;
    ~A() = default;
    int a;
};

int main()
{
    std::cout << std::boolalpha <<
        std::is_trivially_copy_assignable_v<A> << " " <<
        std::is_trivially_copy_constructible_v<A> << " " <<
        std::is_trivially_move_assignable_v<A> << " " <<
        std::is_trivially_move_constructible_v<A> << " " <<
        std::is_trivially_destructible_v<A> << " " <<
        std::is_trivially_copyable_v<A> << "\n";
    return 0;
}

И выход false false false false false true. Но согласно cppreference:

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

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

Таким образом, из первых четырех логических выходных данных ни один из конструктора копирования, конструктора перемещения, оператора присваивания копирования и оператора присваивания перемещения не является тривиальным, поэтому он должен быть нетривиально копируемым; Однако последним выходным логическим значением является true.

Примечание. Вы можете сделать ~A() = default и A() = default общедоступными, чтобы создавать объекты, но основной вопрос остается прежним.

Просто для полноты: какой компилятор и стандартную версию вы использовали?

Sebastian 13.02.2023 09:56

@Sebastian Я пробовал gcc 12.2 и msvc 19.29. Стандартная версия C++20.

o_oTurtle 13.02.2023 09:57

@ ALX23z Не могли бы вы указать, как это требование соответствует приведенному определению / стандартной формулировке?

Sebastian 13.02.2023 10:00

@ Себастьян, ты попал в серую зону. Что-то, что никто никогда не удосужился проверить, потому что никто никогда не использовал это. Делая большинство конструкторов/назначений закрытыми, класс фактически непригоден для использования. Я не думаю, что авторы стандарта учитывали такие случаи, когда писали его.

ALX23z 13.02.2023 10:03

из первых четырех логических выходных данных ни один из конструктора копирования, конструктора перемещения, оператора присваивания копирования и оператора присваивания перемещения не является тривиальным. Это не то, что проверяют черты is_trivially....

Language Lawyer 13.02.2023 10:30

Похоже, проблема вызвана изначально неправильной формулировкой в ​​стандарте, которая была рассмотрена в CWG 1734 , но кажется, что она все еще не реализована ни в gcc , ни в clang, а в обсуждении clang упоминаются возможные проблемы с abi в случае исправления.

dewaffled 13.02.2023 10:38

@LanguageLawyer Err ... Это довольно косвенно, если ctor копирования класса тривиален, а std::is_trivially_copy_constructible_v ложно.

o_oTurtle 13.02.2023 10:43

Это довольно косвенно, если ctor копирования класса тривиален, а std::is_trivially_copy_constructible_v ложно. Почему? В конце концов, это не говорит std::has_trivial_copy_constructor_v.

Language Lawyer 13.02.2023 10:45
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
13
8
1 033
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вопрос не в том, можно ли скопировать экземпляр этого класса?

std::is_trivially_copyable ответы

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

Это связано с тем, что класс A имеет подходящий конструктор перемещения, который является тривиальным. Более того, он также имеет тривиальный неудаляемый деструктор, и поэтому класс A удовлетворяет всем требованиям, приведенным ниже, из тривиально копируемого класса:

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

  • который имеет по крайней мере один допустимый конструктор копирования, конструктор перемещения, оператор присваивания копирования или оператор присваивания перемещения

  • где каждый допустимый конструктор копирования, конструктор перемещения, оператор присваивания копирования и присваивание перемещения оператор тривиален и

  • который имеет тривиальный неудаляемый деструктор (11.4.7).

(выделено мной)

Обратите внимание на акцент, по крайней мере, что означает, что класс A удовлетворяет всем 3 вышеуказанным требованиям.


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

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

  • деструктор не виртуальный

  • все прямые базовые классы его класса имеют тривиальные деструкторы, и

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


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

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

  • класс X не имеет виртуальных функций (11.7.3) и виртуальных базовых классов (11.7.2), и

  • конструктор, выбранный для копирования/перемещения каждого прямого подобъекта базового класса, тривиален, и

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

Проблема в том, что, скажем, он сообщает, что деструктор не тривиален по признакам типа. Таким образом, некоторые из заявленных значений определенно неверны.

ALX23z 13.02.2023 10:28

@ ALX23z Я думаю, вы неправильно поняли, что означают первые четыре черты.

Jason Liam 13.02.2023 10:33

std::is_trivially_copy_constructible_v<T> не проверяет, есть ли у T тривиальный конструктор копирования, на котором основан тривиально-копируемый.

Вместо этого он проверяет, является ли определение переменной формы

T t(u);

где u — переменная типа const T, будет правильно сформирована в контексте, не связанном с T, и что при построении переменной будут использоваться только тривиальные функции. Это включает проверку на доступность и проверку на неудаленный доступный деструктор.

То же самое относится в аналогичной форме к другим чертам _constructible_ и _assignable_. Эти черты не имеют прямого отношения к is_trivially_copyable. Черта is_trivially_copyable говорит вам, можете ли вы использовать memcpy для копирования объектов этого типа. Он не говорит вам, будет ли копирование/перемещение-конструкция/присваивание возможным и тривиальным, для чего и нужны другие трейты.

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