Copy constructors
Конструктор копирования — это конструктор , который может быть вызван с аргументом того же типа класса и копирует содержимое аргумента без его изменения.
Содержание |
Синтаксис
class-name
(
parameter-list
);
|
(1) | ||||||||
class-name
(
parameter-list
)
function-body
|
(2) | ||||||||
class-name
(
single-parameter-list
) = default;
|
(3) | (начиная с C++11) | |||||||
class-name
(
parameter-list
) = delete;
|
(4) | (начиная с C++11) | |||||||
class-name
::
class-name
(
parameter-list
)
function-body
|
(5) | ||||||||
class-name
::
class-name
(
single-parameter-list
) = default;
|
(6) | (начиная с C++11) | |||||||
| class-name | - | класс, для которого объявляется конструктор копирования |
| parameter-list | - |
непустой
список параметров
, удовлетворяющий всем следующим условиям:
|
| single-parameter-list | - | список параметров , состоящий только из одного параметра типа T & , const T & , volatile T & или const volatile T & и не имеющий аргумента по умолчанию |
| function-body | - | тело функции конструктора копирования |
Объяснение
struct X { X(X& other); // конструктор копирования // X(X other); // Ошибка: неверный тип параметра }; union Y { Y(Y& other, int num = 1); // конструктор копирования с несколькими параметрами // Y(Y& other, int num); // Ошибка: у `num` отсутствует аргумент по умолчанию };
Конструктор копирования вызывается всякий раз, когда объект инициализируется (с помощью прямой инициализации или копирующей инициализации ) из другого объекта того же типа (если только разрешение перегрузки не выбирает более подходящее соответствие или вызов не исключается ), что включает
-
инициализация:
T a
=
b
;
или
T a
(
b
)
;
, где
b
имеет тип
T; -
передача аргумента в функцию:
f
(
a
)
;
, где
a
имеет тип
Tи f объявлена как void f ( T t ) ; -
возврат из функции:
return
a
;
внутри функции вида
T f
(
)
, где
a
имеет тип
T, который не имеет move constructor .
Неявно объявленный конструктор копирования
Если для типа класса не предоставлены пользовательские конструкторы копирования, компилятор всегда объявляет конструктор копирования как не- 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 . |
(since C++11) |
Неявно объявленный (или defaulted при первом объявлении) конструктор копирования имеет спецификацию исключений, как описано в динамической спецификации исключений (до C++17) спецификации noexcept (начиная с C++17) .
Неявно определенный конструктор копирования
Если неявно объявленный конструктор копирования не удален, он определяется (то есть генерируется и компилируется тело функции) компилятором, если odr-used или needed for constant evaluation (since C++11) . Для объединений неявно определенный конструктор копирования копирует представление объекта (как с помощью std::memmove ). Для классовых типов, не являющихся объединениями, конструктор выполняет полное почленное копирование прямых базовых подобъектов и подобъектов-членов объекта в порядке их инициализации, используя прямое инициализирование. Для каждого нестатического члена данных ссылочного типа конструктор копирования привязывает ссылку к тому же объекту или функции, к которой привязана исходная ссылка.
|
Если это удовлетворяет требованиям constexpr конструктора (до C++23) constexpr функции (начиная с C++23) , то генерируемый конструктор копирования является constexpr .
Генерация неявно определенного конструктора копирования устарела, если
|
(начиная с C++11) |
Удаленный конструктор копирования
Неявно объявленный
или явно заданный по умолчанию
(since C++11)
конструктор копирования для класса
T
является
неопределенным
(until C++11)
определен как удаленный
(since C++11)
если выполняется любое из следующих условий:
|
(начиная с C++11) |
-
Tимеет потенциально конструируемый подобъект типа классаM(или, возможно, многомерный массив таких) такой, что
-
-
Mимеет деструктор, который удален или (начиная с C++11) недоступен из конструктора копирования, или -
разрешение перегрузки, примененное для поиска
M's конструктора копирования
-
- не приводит к пригодному кандидату, или
- в случае, когда подобъект является variant member , выбирает нетривиальную функцию.
-
|
Неявно объявленный конструктор копирования для класса
|
(since C++11) |
Тривиальный конструктор копирования
Конструктор копирования для класса
T
является тривиальным, если выполняются все следующие условия:
- он не предоставлен пользователем (то есть является неявно определённым или заданным по умолчанию);
-
Tне имеет виртуальных функций-членов; -
Tне имеет виртуальных базовых классов; -
конструктор копирования, выбранный для каждого прямого базового класса
T, является тривиальным; -
конструктор копирования, выбранный для каждого нестатического члена классового типа (или массива классового типа)
T, является тривиальным;
Тривиальный конструктор копирования для необъединенного класса эффективно копирует каждый скалярный подобъект (включая, рекурсивно, подобъекты подобъектов и так далее) аргумента и не выполняет других действий. Однако байты заполнения не обязательно копировать, и даже представления объектов скопированных подобъектов не обязаны быть идентичными, пока их значения совпадают.
TriviallyCopyable объекты могут быть скопированы путём ручного копирования их объектных представлений, например, с помощью std::memmove . Все типы данных, совместимые с языком C (POD-типы), являются тривиально копируемыми.
Подходящий конструктор копирования
|
Конструктор копирования является подходящим, если он либо объявлен пользователем, либо одновременно неявно объявлен и может быть определен. |
(until C++11) |
|
Конструктор копирования является подходящим, если он не удален. |
(since C++11)
(until C++20) |
|
Конструктор копирования является подходящим, если удовлетворены все следующие условия:
|
(since C++20) |
Тривиальность подходящих конструкторов копирования определяет, является ли класс типом с неявным временем жизни , и является ли класс тривиально копируемым типом .
Примечания
Во многих ситуациях конструкторы копирования исключаются оптимизацией, даже если они могут производить наблюдаемые побочные эффекты, см. copy elision .
Пример
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++.
| DR | Применяется к | Поведение в опубликованной версии | Корректное поведение |
|---|---|---|---|
| CWG 1353 | C++98 |
условия, при которых неявно объявленные конструкторы копирования
являются неопределенными, не учитывали многомерные массивы |
учитывать эти типы |
| CWG 2094 | C++11 | volatile-члены делают копирование нетривиальным ( CWG issue 496 ) | тривиальность не затрагивается |
| CWG 2171 | C++11 | X ( X & ) = default был нетривиальным | сделан тривиальным |
| CWG 2595 | C++20 |
конструктор копирования не был подходящим, если существует
другой конструктор копирования, который более ограничен но не удовлетворяет своим связанным ограничениям |
он может быть подходящим в этом случае |