Конструкторы копирования
Конструктор копирования — это конструктор, который может быть вызван с аргументом того же типа класса и копирует содержимое аргумента, не изменяя его.
Синтаксис
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&, constT&, volatileT& или constvolatileT&, у которого нет аргумента по умолчанию |
| function-body | - | тело функции конструктора копирования |
Пояснение
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, у которого нет конструктора перемещения.
Неявно объявленный конструктор копирования
Если для типа класса не предоставлены пользовательские конструкторы копирования, компилятор всегда объявляет конструктор копирования как не-explicit-член класса с доступом inlinepublic. Этот неявно объявленный конструктор копирования имеет форму T::T(const T&), если выполняются все следующие условия:
- у каждой прямой и виртуальной базовой
BклассаTесть конструктор копирования, параметры которого имеют тип constB& или constvolatileB&; - у каждого нестатического члена данных
MклассаT, имеющего тип класса или массив класса, есть конструктор копирования, параметры которого имеют тип constM& или constvolatileM&.
В противном случае неявно объявленный конструктор копирования имеет форму T::T(T&).
В силу этих правил неявно объявленный конструктор копирования не может привязаться к аргументу-левостороннему значению типа volatile.
У класса может быть несколько конструкторов копирования, например, и 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), если выполняется любое из следующих условий:
| (начиная с C++11) |
-
Tимеет потенциально конструируемый подобъект типа классаM(или, возможно, многомерный массив такого типа), для которого -
Mимеет деструктор, который удалён или(начиная с C++11) недоступен из конструктора копирования, или - разрешение перегрузки, применённое для поиска конструктора копирования
M, - не находит пригодного кандидата, или
- если подобъект является вариативным членом, выбирает нетривиальную функцию.
| Неявно объявленный конструктор копирования класса | (начиная с C++11) |
Тривиальный конструктор копирования
Конструктор копирования класса T является тривиальным, если выполняются все следующие условия:
- он не предоставлен пользователем (то есть неявно определён или задан по умолчанию);
-
Tне имеет виртуальных функций-членов; -
Tне имеет виртуальных базовых классов; - конструктор копирования, выбранный для каждой прямой базовой
T, является тривиальным; - конструктор копирования, выбранный для каждого нестатического члена
Tтипа класса (или массива класса), является тривиальным;
Тривиальный конструктор копирования для класса, не являющегося объединением, фактически копирует каждый скалярный подобъект аргумента (включая рекурсивно подобъекты подобъектов и так далее) и не выполняет никаких других действий. Однако байты заполнения копировать не обязательно, и представления объектов копируемых подобъектов могут различаться, если их значения одинаковы.
Объекты типа TriviallyCopyable можно копировать вручную, копируя их представления объектов, например, с помощью std::memmove. Все типы данных, совместимые с языком C (типы POD), являются тривиально копируемыми.
Подходящий конструктор копирования
| Конструктор копирования является подходящим, если он объявлен пользователем либо одновременно неявно объявлен и может быть определён. | (до C++11) |
| Конструктор копирования является подходящим, если он не удалён. |
(начиная с C++11) (до C++20) |
| Конструктор копирования является подходящим, если выполняются все следующие условия:
| (начиная с C++20) |
Тривиальность подходящих конструкторов копирования определяет, является ли класс типом с неявным временем жизни и является ли класс тривиально копируемым типом.
Примечания
Во многих ситуациях вызовы конструкторов копирования оптимизируются даже в том случае, если они могли бы иметь наблюдаемые побочные эффекты; см. устранение копирования.
Пример
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
}
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были ретроактивно применены к ранее опубликованным стандартам C++.
| Отчёт об ошибке | Применён к | Опубликованное поведение | Правильное поведение |
|---|---|---|---|
| CWG 1353 | C++98 | условия, при которых неявно объявленные конструкторы копирования не определялись, не учитывали многомерные массивы | учитывать такие типы |
| CWG 2094 | C++11 | члены volatile делают копирование нетривиальным (отчёт CWG 496) | тривиальность не затрагивается |
| CWG 2171 | C++11 |
X(X&) = default был нетривиальным | сделан тривиальным |
| CWG 2595 | C++20 | конструктор копирования не считался подходящим, если существовал другой, более ограниченный конструктор копирования, связанные ограничения которого не выполнялись | в этом случае он может быть подходящим |
См. также
- преобразующий конструктор
- копирующее присваивание
- устранение копирования
- конструктор по умолчанию
- деструктор
explicit- инициализация
- перемещающее присваивание
- конструктор перемещения
new
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/copy_constructor