Spec-Zone.ru › C++

Копирующие конструкторы

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

Синтаксис

имя-класса (список-параметров ); (1)
имя-класса (список-параметров ) тело-функции (2)
имя-класса (список-из-одного-параметра ) = default; (3) (с C++11)
имя-класса (список-параметров ) = delete; (4) (с C++11)
имя-класса ::имя-класса (список-параметров ) тело-функции (5)
имя-класса ::имя-класса (список-из-одного-параметра ) = default; (6) (с C++11)
имя-класса - класс, для которого объявляется копирующий конструктор
список-параметров - непустой список параметров, удовлетворяющий всем следующим условиям:
  • учитывая тип класса как T, первый параметр имеет тип T&, const T&, volatile T& или const volatile T&, и
  • либо других параметров нет, либо все остальные параметры имеют значения по умолчанию.
список-из-одного-параметра - список параметров из одного параметра, который имеет тип T&, const T&, volatile T& или const volatile T& и не имеет значения по умолчанию
тело-функции - тело функции копирующего конструктора

Объяснение

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

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

(с C++11)

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

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

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

Явно объявленный конструктор копирования для класса T определяется как удалённый, если T объявляет конструктор перемещения или оператор перемещения присваивания.

(с 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API