Пространства имён
Варианты
Действия

Конструкторы копирования

Материал из cppreference.com
< cpp‎ | language
 
 
 
 

Конструктор копирования класса T это нешаблонный конструктор, первый параметр которого равен T&‍, const T&‍, volatile T&‍ или const volatile T&‍, и либо другие параметры отсутствуют, либо все остальные параметры имеют значения по умолчанию.

Содержание

[править] Синтаксис

имя-класса ( const имя-класса & ) (1)
имя-класса ( const имя-класса & ) = default; (2) (начиная с C++11)
имя-класса ( const имя-класса & ) = delete; (3) (начиная с C++11)

Где имя-класса должно именовать текущий класс (или текущую реализацию шаблона класса), или, при объявлении в области видимости пространства имён или в объявлении друга, оно должно быть полным именем класса.

[править] Объяснение

1) Типичное объявление конструктора копирования.
2) Принудительное создание конструктора копирования компилятором.
3) Предотвращает неявное создание конструктора копирования.

Конструктор копирования вызывается всякий раз, когда объект инициализируется (путём прямой инициализации или инициализации копированием) из другого объекта того же типа (кроме случаев, когда разрешение перегрузки выбирает лучшее совпадение или вызов пропускается), что включает

  • инициализацию: T a = b; или T a(b);, где b имеет тип T;
  • передачу аргумента функции: f(a);, где a имеет тип T и f имеет тип void f(T t);
  • возврат из функции: return a; внутри такой функции, как T f(), где a имеет тип T, который не имеет конструктора перемещения.

[править] Неявно объявленный конструктор копирования

Если для классового типа (struct, class или union) не предусмотрены пользовательские конструкторы копирования, компилятор всегда будет объявлять конструктор копирования как не explicit inline public элемент своего класса. Этот неявно объявленный конструктор копирования имеет форму T::T(const T&), если выполняются все следующие условия:

  • каждый прямой и виртуальный базовый класс B класса T имеет конструктор копирования, параметрами которого являются const B& или const volatile B&;
  • каждый нестатический элемент данных M из T классового типа или массива классового типа имеет конструктор копирования, параметры которого равны const M& или const volatile M&.

В противном случае неявно объявленный конструктор копирования имеет вид T::T(T&). (Обратите внимание, что из-за этих правил неявно объявленный конструктор копирования не может связываться с volatile lvalue аргументом.)

Класс может иметь несколько конструкторов копирования, например T::T(const T&) и T::T(T&).

Если присутствуют некоторые определяемые пользователем конструкторы копирования, пользователь всё равно может принудительно сгенерировать неявно объявленный конструктор копирования с ключевым словом default.

(начиная с C++11)

Неявно объявленный (или заданный по умолчанию при первом объявлении) конструктор копирования имеет спецификацию исключения, как описано в спецификации динамических исключений (до C++17)спецификации noexcept (начиная с C++17).

[править] Удаление неявно объявленного конструктора копирования

Неявно объявленный конструктор копирования для класса T не определён, если выполняется любое из следующих условий:

(до C++11)

Неявно объявленный или заданный по умолчанию конструктор копирования для класса T определяется как удалённый, если выполняется любое из следующих условий:

(начиная с C++11)
  • T имеет нестатические элементы данных, которые нельзя скопировать (имеют удалённые, недоступные или неоднозначные конструкторы копирования);
  • T имеет прямой или виртуальный базовый класс, который нельзя скопировать (имеет удалённые, недоступные или неоднозначные конструкторы копирования);
  • T имеет прямой или виртуальный базовый класс или нестатический элемент данных с удалённым или недоступным деструктором;
  • T является классом, подобным объединению, и имеет вариантный элемент с нетривиальным конструктором копирования;
  • T имеет элемент данных ссылочного типа rvalue;
  • T имеет определяемый пользователем конструктор перемещения или оператор присваивания перемещением (это условие вызывает удаление только неявно объявленного, а не заданного по умолчанию конструктора копирования).
(начиная с C++11)

[править] Тривиальный конструктор копирования

Конструктор копирования для класса T тривиален, если выполняются все следующие условия:

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

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

Объекты TriviallyCopyable можно копировать, копируя их объектные представления вручную, например с std::memmove. Все типы данных, совместимые с языком C (типы POD), копируются тривиально.

[править] Доступный конструктор копирования

Конструктор копирования доступен, если он либо объявлен пользователем, либо неявно объявлен и определён.

(до C++11)

Конструктор копирования доступен, если он не удалён.

(начиная с C++11)
(до C++20)

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

(начиная с C++20)

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

[править] Неявно определённый конструктор копирования

Если неявно объявленный конструктор копирования не удалён, он определяется (то есть тело функции генерируется и компилируется) компилятором, если используется odr или необходим для константной оценки (начиная с C++11). Для типов объединения неявно определённый конструктор копирования копирует представление объекта (как std::memmove). Для классовых типов не объединений (class и struct) конструктор выполняет полное поэлементное копирование базовых классов объекта и нестатических элементов в порядке их инициализации, используя прямую инициализацию. Если он соответствует требованиям constexpr конструктора, созданным конструктором копирования является constexpr. (начиная с C++11)

Генерация неявно определённого конструктора копирования устарела, если T имеет определяемый пользователем деструктор или определяемый пользователем оператор присваивания копированием.

(начиная с C++11)

[править] Примечание

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

[править] Пример

struct A
{
    int n;
    A(int n = 1) : n(n) { }
    A(const A& a) : n(a.n) { } // пользовательский конструктор копирования
};
 
struct B : A
{
    // неявный конструктор по умолчанию B::B()
    // неявный конструктор копирования B::B(const B&)
};
 
struct C : B
{
     C() : B() { }
 private:
     C(const C&); // не копируемый, в стиле C++98
};
 
int main()
{
    A a1(7);
    A a2(a1); // вызывает конструктор копирования
    B b;
    B b2 = b;
    A a3 = b; // преобразование в A& и конструктор копирования
    volatile A va(10);
    // A a4 = va; // ошибка компиляции
 
    C c;
    // C c2 = c; // ошибка компиляции
}

[править] Отчёты о дефектах

Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:

Номер Применён Поведение в стандарте Корректное поведение
CWG 2094 C++11 volatile элементы делают копирование нетривиальным (CWG 496) тривиальность не имеет эффекта
CWG 2171 C++11 X(X&) = default было нетривиальным сделано тривиальным

[править] Смотрите также