Копирующие конструкторы
Копирующий конструктор — это конструктор, который можно вызвать с аргументом того же типа класса и копирует содержимое аргумента без изменения самого аргумента.
Синтаксис
имя-класса (список-параметров ); | (1) | |
имя-класса (список-параметров ) тело-функции | (2) | |
имя-класса (список-из-одного-параметра ) = default; | (3) | (с C++11) |
имя-класса (список-параметров ) = delete; | (4) | (с C++11) |
имя-класса ::имя-класса (список-параметров ) тело-функции | (5) | |
имя-класса ::имя-класса (список-из-одного-параметра ) = default; | (6) | (с C++11) |
| имя-класса | - | класс, для которого объявляется копирующий конструктор |
| список-параметров | - | непустой список параметров, удовлетворяющий всем следующим условиям:
|
| список-из-одного-параметра | - | список параметров из одного параметра, который имеет тип T&, const T&, volatile T& или const volatile T& и не имеет значения по умолчанию |
| тело-функции | - | тело функции копирующего конструктора |
Объяснение
struct X
{
X(X& other); // copy constructor
// X(X other); // Error: incorrect parameter type
};
union Y
{
Y(Y& other, int num = 1); // copy constructor with multiple parameters
// Y(Y& other, int num); // Error: `num` has no default argument
};Копирующий конструктор вызывается всякий раз, когда объект инициализируется (с помощью прямой инициализации или копирующей инициализации) из другого объекта того же типа (если разрешение перегрузки не выбирает лучшего совпадения или вызов исключается), что включает
- инициализация:
T a = b;илиT a(b);, гдеbимеет типT; - передача аргументов в функцию:
f(a);, гдеaимеет типTиfявляетсяvoid f(T t); - возврат значения функции:
return a;внутри функции, такой какT f(), гдеaимеет типT, у которой нет конструктора перемещения.
Неявный копирующий конструктор
Если для типа класса не предоставлены пользовательские копирующие конструкторы, компилятор всегда объявит копирующий конструктор как неявный 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).
Неявно определенный копирующий конструктор
Если неявный копирующий конструктор не удалён, он определен (то есть тело функции сгенерировано и скомпилировано) компилятором, если он используется в соответствии с правилом одного определения (ODR) или необходим для вычисления константного выражения(с C++11). Для объединений типов копирующий конструктор копирует представление объекта (как в std::memmove). Для классов, не являющихся объединениями, конструктор выполняет полную копию членов объекта, баз и нестатических членов, в порядке их инициализации, используя прямую инициализацию.
| Если это удовлетворяет требованиям constexpr конструктора(до C++23)constexpr функции(с C++23), сгенерированный копирующий конструктор будет constexpr. Генерация неявно определенного копирующего конструктора устарела, если | (с C++11) |
Удаленный копирующий конструктор
Неявно объявленный или явным образом заданный по умолчанию(с C++11) копирующий конструктор для класса T определён как удаленный (не определён)(до C++11) если выполняется любое из следующих условий:
| (с C++11) |
-
Tимеет потенциально построенный подобъект типа классаM(или, возможно, многомерный массив этого типа) такой, что - у
Mесть деструктор, который удален или(с C++11) недоступен из копирующего конструктора, или - разрешение перегрузки при поиске копирующего конструктора
M - не приводит к подходящей кандидатуре, или
- в случае, если подобъектом является член-вариант, выбирает нетривиальную функцию.
| Явно объявленный конструктор копирования для класса | (с C++11) |
Trivial copy constructor
Конструктор копирования для класса T является тривиальным, если выполняются все следующие условия:
- он не задан пользователем (то есть, он неявно определён или задан по умолчанию);
-
Tне содержит виртуальных членов-функций; -
Tне содержит виртуальных базовых классов; - конструктор копирования, выбранный для каждого непосредственного базового класса
Tявляется тривиальным; - конструктор копирования, выбранный для каждого нестатического класса (или массива класса) члена
Tявляется тривиальным;
Тривиальный конструктор копирования для класса, не являющегося объединением, эффективно копирует каждый скалярный подобъект (включая, рекурсивно, подобъекты подобъектов и так далее) аргумента и не выполняет никаких других действий. Однако, байты заполнения копировать не обязательно, и даже представления объектов скопированных подобъектов не обязательно должны быть одинаковыми, при условии, что их значения идентичны.
Тип, тривиально копируемый объекты могут быть скопированы путём копирования их представления объекта вручную, например, с помощью std::memmove. Все типы данных, совместимые с языком C (POD-типы), тривиально копируются.
Eligible copy constructor
| Конструктор копирования считается допустимым, если он либо задан пользователем, либо объявлен неявно и определяем. | (до C++11) |
| Конструктор копирования считается допустимым, если он не удалён. |
(с C++11) (до C++20) |
| Конструктор копирования считается допустимым, если
| (с C++20) |
Тривиальность допустимых конструкторов копирования определяет, является ли класс типом с неявным временем жизни и является ли класс типом, тривиально копируемым.
Notes
Во многих ситуациях конструкторы копирования оптимизируются даже если они приведут к наблюдаемым побочным эффектам, см. исключение копирования.
Example
struct A
{
int n;
A(int n = 1) : n(n) {}
A(const A& a) : n(a.n) {} // user-defined copy constructor
};
struct B : A
{
// implicit default constructor B::B()
// implicit copy constructor B::B(const B&)
};
struct C : B
{
C() : B() {}
private:
C(const C&); // non-copyable, C++98 style
};
int main()
{
A a1(7);
A a2(a1); // calls the copy constructor
B b;
B b2 = b;
A a3 = b; // conversion to A& and copy constructor
volatile A va(10);
// A a4 = va; // compile error
C c;
// C c2 = c; // compile error
}Defect reports
Следующие изменения поведения, связанные с ошибками, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применимо к | Поведение, как опубликовано | Правильное поведение |
|---|---|---|---|
| CWG 1353 | C++98 | условия, при которых неявно объявленные конструкторы копирования были неопределёнными, не учитывали многомерные типы массивов | учитывать эти типы |
| CWG 2094 | C++11 | volatile члены делают копирование нетривиальным (CWG issue 496) | тривиальность не затрагивается |
| CWG 2171 | C++11 |
X(X&) = default был нетривиальным | стал тривиальным |
See also
- конвертирующий конструктор
- оператор копирующего присваивания
- исключение копирования
- конструктор по умолчанию
- деструктор
-
explicit - инициализация
- перемещающее присваивание
- конструктор перемещения
-
new
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/copy_constructor