Namespaces
Variants

Copy constructors

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Конструктор копирования — это конструктор , который может быть вызван с аргументом того же типа класса и копирует содержимое аргумента без его изменения.

Содержание

Синтаксис

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 - непустой список параметров , удовлетворяющий всем следующим условиям:
  • для заданного типа класса T первый параметр имеет тип T & , const T & , volatile T & или const volatile T & , и
  • либо других параметров нет, либо все остальные параметры имеют аргументы по умолчанию .
single-parameter-list - список параметров , состоящий только из одного параметра типа T & , const T & , volatile T & или const volatile T & и не имеющий аргумента по умолчанию
function-body - тело функции конструктора копирования

Объяснение

1) Объявление конструктора копирования внутри определения класса.
2-4) Определение конструктора копирования внутри определения класса.
3) Конструктор копирования явно объявлен как используемый по умолчанию.
4) Конструктор копирования удалён.
5,6) Определение конструктора копирования вне определения класса (класс должен содержать объявление (1) ).
6) Конструктор копирования явно объявлен стандартным.
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 .

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

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

Удаленный конструктор копирования

Неявно объявленный или явно заданный по умолчанию (since C++11) конструктор копирования для класса T является неопределенным (until C++11) определен как удаленный (since C++11) если выполняется любое из следующих условий:

  • T имеет нестатический член данных типа rvalue-ссылки.
(начиная с C++11)
  • M имеет деструктор, который удален или (начиная с C++11) недоступен из конструктора копирования, или
  • разрешение перегрузки, примененное для поиска M 's конструктора копирования
  • не приводит к пригодному кандидату, или
  • в случае, когда подобъект является variant member , выбирает нетривиальную функцию.

Неявно объявленный конструктор копирования для класса T определяется как удаленный, если T объявляет move constructor или move assignment operator .

(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 конструктор копирования не был подходящим, если существует
другой конструктор копирования, который более ограничен
но не удовлетворяет своим связанным ограничениям
он может быть подходящим в этом случае

Смотрите также