Конструкторы копирования
Конструктор копирования класса T это нешаблонный конструктор, первый параметр которого равен T&, const T&, volatile T& или const volatile T&, и либо другие параметры отсутствуют, либо все остальные параметры имеют значения по умолчанию.
[править] Синтаксис
имя-класса ( const имя-класса & )
|
(1) | ||||||||
имя-класса ( const имя-класса & ) = default;
|
(2) | (начиная с C++11) | |||||||
имя-класса ( const имя-класса & ) = delete;
|
(3) | (начиная с C++11) | |||||||
Где имя-класса должно именовать текущий класс (или текущую реализацию шаблона класса), или, при объявлении в области видимости пространства имён или в объявлении друга, оно должно быть полным именем класса.
[править] Объяснение
Конструктор копирования вызывается всякий раз, когда объект инициализируется (путём прямой инициализации или инициализации копированием) из другого объекта того же типа (кроме случаев, когда разрешение перегрузки выбирает лучшее совпадение или вызов пропускается), что включает
- инициализацию: 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&).
|
Если присутствуют некоторые определяемые пользователем конструкторы копирования, пользователь всё равно может принудительно сгенерировать неявно объявленный конструктор копирования с ключевым словом |
(начиная с C++11) |
Неявно объявленный (или заданный по умолчанию при первом объявлении) конструктор копирования имеет спецификацию исключения, как описано в спецификации динамических исключений (до C++17)спецификации noexcept (начиная с C++17).
[править] Удаление неявно объявленного конструктора копирования
|
Неявно объявленный конструктор копирования для класса |
(до C++11) |
|
Неявно объявленный или заданный по умолчанию конструктор копирования для класса |
(начиная с C++11) |
-
Tимеет нестатические элементы данных, которые нельзя скопировать (имеют удалённые, недоступные или неоднозначные конструкторы копирования); -
Tимеет прямой или виртуальный базовый класс, который нельзя скопировать (имеет удалённые, недоступные или неоднозначные конструкторы копирования); -
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)
|
Генерация неявно определённого конструктора копирования устарела, если |
(начиная с 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 было нетривиальным | сделано тривиальным |