Namespaces
Variants

Copy assignment operator

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

Оператор копирующего присваивания — это нешаблонная нестатическая функция-член с именем operator = , которая может быть вызвана с аргументом того же типа класса и копирует содержимое аргумента без его изменения.

Содержание

Синтаксис

Для синтаксиса формального оператора присваивания копированием см. объявление функции . Приведенный ниже список синтаксисов демонстрирует только подмножество всех допустимых вариантов синтаксиса оператора присваивания копированием.

тип-возвращаемого-значения operator=( список-параметров  ); (1)
тип-возвращаемого-значения operator=( список-параметров  ) тело-функции (2)
тип-возвращаемого-значения operator=( список-параметров-без-умолчаний  ) = default; (3) (начиная с C++11)
тип-возвращаемого-значения operator=( список-параметров  ) = delete; (4) (начиная с C++11)
тип-возвращаемого-значения имя-класса  :: operator=( список-параметров  ) тело-функции (5)
тип-возвращаемого-значения имя-класса  :: operator=( список-параметров-без-умолчаний  ) = default; (6) (начиная с C++11)
class-name - класс, для которого объявляется оператор присваивания копированием; тип класса обозначен как T в описаниях ниже
parameter-list - список параметров только из одного параметра типа T , T& , const T & , volatile T & или const volatile T &
parameter-list-no-default - список параметров только из одного параметра типа T , T& , const T & , volatile T & или const volatile T & без аргумента по умолчанию
function-body - тело функции оператора присваивания копированием
return-type - любой тип, но предпочтительно T& для возможности цепочки присваиваний

Объяснение

1) Объявление оператора копирующего присваивания внутри определения класса.
2-4) Определение оператора присваивания копированием внутри определения класса.
3) Оператор копирующего присваивания является явно заданным по умолчанию.
4) Оператор копирующего присваивания удален.
5,6) Определение оператора копирующего присваивания вне определения класса (класс должен содержать объявление (1) ).
6) Оператор копирующего присваивания явно объявлен по умолчанию.
struct X
{
    X& operator=(X& other);     // оператор копирующего присваивания
    X operator=(X other);       // передача по значению разрешена
//  X operator=(const X other); // Ошибка: неверный тип параметра
};
union Y
{
    // операторы копирующего присваивания могут иметь синтаксисы, не перечисленные выше,
    // при условии, что они следуют общему синтаксису объявления функций
    // и не нарушают ограничения, перечисленные выше
    auto operator=(Y& other) -> Y&;       // OK: завершающий тип возврата
    Y& operator=(this Y& self, Y& other); // OK: явный параметр объекта
//  Y& operator=(Y&, int num = 1);        // Ошибка: содержит другие необъектные параметры
};

Оператор копирующего присваивания вызывается всякий раз, когда он выбран разрешением перегрузки , например, когда объект появляется в левой части выражения присваивания.

Неявно объявленный оператор присваивания копированием

Если для типа класса не предоставлены пользовательские операторы копирующего присваивания, компилятор всегда объявляет его как inline public член класса. Этот неявно объявленный оператор копирующего присваивания имеет форму T & T :: operator = ( const T & ) если выполняются все следующие условия:

  • каждый прямой базовый класс B типа T имеет оператор присваивания копией, параметры которого имеют тип B или const B & или const volatile B & ;
  • каждый нестатический элемент данных M типа T классового типа или массива классового типа имеет оператор присваивания копией, параметры которого имеют тип M или const M & или const volatile M & .

В противном случае неявно объявленный оператор присваивания копированием объявляется как T & T :: operator = ( T & ) .

В соответствии с этими правилами, неявно объявленный оператор копирующего присваивания не может связываться с volatile lvalue аргументом.

Класс может иметь несколько операторов присваивания копированием, например, как T & T :: operator = ( T & ) , так и T & T :: operator = ( T ) . Если присутствуют пользовательские операторы присваивания копированием, пользователь может принудительно сгенерировать неявно объявленный оператор присваивания с помощью ключевого слова default . (начиная с C++11)

Неявно объявленный (или defaulted при первом объявлении) оператор копирующего присваивания имеет спецификацию исключений, как описано в динамической спецификации исключений (до C++17) спецификации noexcept (начиная с C++17)

Поскольку оператор копирующего присваивания всегда объявляется для любого класса, оператор присваивания базового класса всегда скрыт. Если using-объявление используется для импорта оператора присваивания из базового класса, и его тип аргумента может совпадать с типом аргумента неявного оператора присваивания производного класса, то using-объявление также скрывается неявным объявлением.

Неявно определённый оператор присваивания копированием

Если неявно объявленный оператор копирующего присваивания не является ни удаленным, ни тривиальным, он определяется (то есть генерируется и компилируется тело функции) компилятором, если odr-used или needed for constant evaluation (since C++14) . Для типов union неявно определенный оператор копирующего присваивания копирует представление объекта (как с помощью std::memmove ). Для типов классов, не являющихся union, оператор выполняет покомпонентное копирующее присваивание прямых базовых классов и нестатических членов-данных объекта в порядке их инициализации, используя встроенное присваивание для скалярных типов, покомпонентное копирующее присваивание для массивов и оператор копирующего присваивания для классовых типов (вызываемый невиртуально).

Неявно определенный оператор копирующего присваивания для класса T является constexpr , если

  • T является literal type , и
  • оператор присваивания, выбранный для копирования каждого прямого базового подобъекта, является constexpr-функцией, и
  • для каждого нестатического члена данных T , который имеет классовый тип (или массив таковых), оператор присваивания, выбранный для копирования этого члена, является constexpr-функцией.
(since C++14)
(until C++23)

Неявно определенный оператор копирующего присваивания для класса T является constexpr .

(since C++23)


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

(since C++11)

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

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

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

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

(since C++11)

Тривиальный оператор копирующего присваивания

Оператор копирующего присваивания для класса T является тривиальным, если выполняются все следующие условия:

  • он не предоставлен пользователем (то есть является неявно определённым или заданным по умолчанию);
  • T не имеет виртуальных функций-членов;
  • T не имеет виртуальных базовых классов;
  • оператор присваивания копией, выбранный для каждого прямого базового класса T , является тривиальным;
  • оператор присваивания копией, выбранный для каждого нестатического члена типа класса (или массива типа класса) T , является тривиальным.

Тривиальный оператор копирующего присваивания создает копию представления объекта, как если бы с помощью std::memmove . Все типы данных, совместимые с языком C (POD-типы), являются тривиально копируемо присваиваемыми.

Подходящий оператор копирующего присваивания

Оператор копирующего присваивания является подходящим, если он либо объявлен пользователем, либо одновременно объявлен неявно и может быть определен.

(до C++11)

Оператор копирующего присваивания является подходящим, если он не удален.

(начиная с C++11)
(до C++20)

Оператор копирующего присваивания является подходящим, если удовлетворены все следующие условия:

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

Тривиальность подходящих операторов копирующего присваивания определяет, является ли класс тривиально копируемым типом .

Примечания

Если предоставлены и оператор копирующего присваивания, и оператор перемещающего присваивания, разрешение перегрузки выбирает перемещающее присваивание, если аргумент является rvalue (либо prvalue , такой как безымянный временный объект, либо xvalue , такой как результат std::move ), и выбирает копирующее присваивание, если аргумент является lvalue (именованный объект или функция/оператор, возвращающие lvalue-ссылку). Если предоставлен только оператор копирующего присваивания, все категории аргументов выбирают его (при условии, что он принимает аргумент по значению или по ссылке на константу, поскольку rvalue могут связываться с константными ссылками), что делает копирующее присваивание резервным вариантом для перемещающего присваивания, когда перемещение недоступно.

Не определено, присваиваются ли подобъекты виртуальных базовых классов, доступные через более чем один путь в решетке наследования, более одного раза неявно определенным оператором копирующего присваивания (то же относится к оператору перемещающего присваивания ).

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

Пример

#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
struct A
{
    int n;
    std::string s1;
    A() = default;
    A(A const&) = default;
    // пользовательское копирующее присваивание (идиома copy-and-swap)
    A& operator=(A other)
    {
        std::cout << "copy assignment of A\n";
        std::swap(n, other.n);
        std::swap(s1, other.s1);
        return *this;
    }
};
struct B : A
{
    std::string s2;
    // неявно определенное копирующее присваивание
};
struct C
{
    std::unique_ptr<int[]> data;
    std::size_t size;
    // пользовательское копирующее присваивание (не по идиоме copy-and-swap)
    // примечание: copy-and-swap всегда перераспределяет ресурсы
    C& operator=(const C& other)
    {
        if (this != &other) // не самоприсваивание
        {
            if (size != other.size) // ресурс не может быть переиспользован
            {
                data.reset(new int[other.size]);
                size = other.size;
            }
            std::copy(&other.data[0], &other.data[0] + size, &data[0]);
        }
        return *this;
    }
};
int main()
{
    A a1, a2;
    std::cout << "a1 = a2 calls ";
    a1 = a2; // пользовательское копирующее присваивание
    B b1, b2;
    b2.s1 = "foo";
    b2.s2 = "bar";
    std::cout << "b1 = b2 calls ";
    b1 = b2; // неявно определенное копирующее присваивание
    std::cout << "b1.s1 = " << b1.s1 << "; b1.s2 = " << b1.s2 << '\n';
}

Вывод:

a1 = a2 calls copy assignment of A
b1 = b2 calls copy assignment of A
b1.s1 = foo; b1.s2 = bar

Отчеты о дефектах

Следующие отчеты об изменениях в поведении, содержащие описания дефектов, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применяется к Поведение в опубликованной версии Корректное поведение
CWG 1353 C++98 условия, при которых неявно объявленные операторы копирующего присваивания
являются неопределенными, не учитывали многомерные массивы
учитывать эти типы
CWG 2094 C++11 volatile подобъект делал операторы копирующего присваивания по умолчанию
нетривиальными ( CWG issue 496 )
тривиальность не затрагивается
CWG 2171 C++11 operator = ( X & ) = default был нетривиальным сделан тривиальным
CWG 2180 C++11 оператор копирующего присваивания по умолчанию для класса T не определялся как удаленный,
если T является абстрактным и имеет прямые виртуальные базовые классы,
не поддерживающие копирующее присваивание
оператор определяется
как удаленный в этом случае
CWG 2595 C++20 оператор копирующего присваивания не был доступен, если существует
другой оператор копирующего присваивания, который является более
ограниченным, но не удовлетворяет своим ассоциированным ограничениям
он может быть доступен
в этом случае

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