Оператор копирующей присваивания
Оператор копирующей присваивания — это нешаблонная нестатическая функция-член с именем operator=, которая может быть вызвана с аргументом того же типа класса и копирует содержимое аргумента, не изменяя сам аргумент.
Синтаксис
Для формального синтаксиса оператора копирующей присваивания см. объявление функции. Нижеприведенный список синтаксиса демонстрирует только часть всех допустимых синтаксисов оператора копирующей присваивания.
тип_возвращаемого_значения operator=(список_параметров ); | (1) | |
тип_возвращаемого_значения operator=(список_параметров ) тело_функции | (2) | |
тип_возвращаемого_значения operator=(список_параметров_без_значений_по_умолчанию ) = default; | (3) | (с C++11) |
тип_возвращаемого_значения operator=(список_параметров ) = delete; | (4) | (с C++11) |
тип_возвращаемого_значения имя_класса ::operator=(список_параметров ) тело_функции | (5) | |
тип_возвращаемого_значения имя_класса ::operator=(список_параметров_без_значений_по_умолчанию ) = default; | (6) | (с C++11) |
| имя_класса | - | класс, для которого объявляется оператор копирующей присваивания, тип класса указан как T в описаниях ниже |
| список_параметров | - | список параметров только с одним параметром, который имеет тип T, T&, const T&, volatile T& или const volatile T& |
| список_параметров_без_значений_по_умолчанию | - | список параметров только с одним параметром, который имеет тип T, T&, const T&, volatile T& или const volatile T&, и у которого нет аргумента по умолчанию |
| тело_функции | - | тело функции оператора копирующей присваивания |
| тип_возвращаемого_значения | - | любой тип, но T& предпочтительнее для возможности цепочки присваиваний |
Объяснение
struct X
{
X& operator=(X& other); // copy assignment operator
X operator=(X other); // pass-by-value is allowed
// X operator=(const X other); // Error: incorrect parameter type
};
union Y
{
// copy assignment operators can have syntaxes not listed above,
// as long as they follow the general function declaration syntax
// and do not viloate the restrictions listed above
auto operator=(Y& other) -> Y&; // OK: trailing return type
Y& operator=(this Y& self, Y& other); // OK: explicit object parameter
// Y& operator=(Y&, int num = 1); // Error: has other non-object parameters
};Оператор копирующей присваивания вызывается всякий раз, когда его выбирает разрешение перегрузки, например, когда объект появляется слева от оператора присваивания.
Неявный оператор копирующей присваивания
Если для типа класса не указан пользовательский оператор копирующей присваивания, компилятор всегда объявляет его как 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)
Неявный (или дефолченный при первом объявлении) оператор копирующей присваивания имеет спецификацию исключений, как описано в спецификации динамических исключений(до C++17)спецификации noexcept(с C++17)
Поскольку оператор копирующей присваивания всегда объявляется для любого класса, оператор присваивания базового класса всегда скрыт. Если используется объявление using для включения оператора присваивания из базового класса, и его тип аргумента может совпадать с типом аргумента неявного оператора присваивания производного класса, объявление using также скрывается неявным объявлением.
Неявно определенный оператор копирующей присваивания
Если неявно объявленный оператор копирующей присваивания не удален и не тривиален, он определяется (то есть, генерируется и компилируется тело функции) компилятором, если odr-используется или необходим для вычисления константного выражения(с C++14). Для типов объединений неявное копирование присваивания копирует представление объекта (как в std::memmove). Для типов классов, не являющихся объединениями, оператор выполняет членное присваивание копирования базовых классов и нестатических членов объекта в порядке их инициализации, используя встроенное присваивание для скаляров и оператор копирующей присваивания для типов классов.
| Неявно определённый оператор копирующей присваивания для класса
|
(с C++14) (до C++23) |
| Неявно определённый оператор копирующей присваивания для класса | (с C++23) |
| Генерация неявно определенного оператора копирования присваивания устарела, если | (с C++11) |
Удаленный оператор копирующей присваивания
Неявно объявленный или явно дефолченный(с C++11) оператор копирующей присваивания для класса T определён как удалённый неопределенный(до C++11)определённый как удалённый(с C++11), если выполнено любое из следующих условий:
-
Tимеет нестатический член данных const-qualified неклассового типа (или, возможно, многомерного массива thereof). -
Tимеет нестатический член данных типа ссылки. -
Tимеет потенциально сконструированный подобъект типа классаM(или, возможно, многомерного массива thereof), такой, что разрешение перегрузки при поиске оператора копирующего присваиванияM - не приводит к пригодной кандидатуре, или
- в случае, если подобъект является вариантным членом, выбирает нетривиальную функцию.
| Неявный оператор копирующей присваивания для класса | (с C++11) |
Оператор тривиального копирующего присваивания
Оператор копирующего присваивания для класса T является тривиальным, если выполняются все следующие условия:
- он не задан пользователем (то есть, он неявно определён или по умолчанию);
-
Tне имеет виртуальных функций-членов; -
Tне имеет виртуальных базовых классов; - оператор копирующего присваивания для каждого непосредственного базового класса
Tявляется тривиальным; - оператор копирующего присваивания для каждого нестатического класса-члена (или массива класса-члена)
Tявляется тривиальным.
Тривиальный оператор копирующего присваивания создаёт копию представления объекта так, как будто он выполняется std::memmove. Все типы данных, совместимые с языком C (POD-типы), тривиально копируемы.
Оператор копирующего присваивания, допускающий использование
| Оператор копирующего присваивания допустим, если он либо задан пользователем, либо неявно объявлен и определяем. | (до C++11) |
| Оператор копирующего присваивания допустим, если он не удалён. |
(с C++11) (до C++20) |
| Оператор копирующего присваивания допустим, если
| (с C++20) |
Тривиальность допустимых операторов копирующего присваивания определяет, является ли класс типом, который тривиально копируется.
Примечания
Если и оператор копирования, и оператор перемещения присваивания предоставляются, решение перегрузки выбирает оператор перемещения присваивания, если аргумент является ссылкой на правое значение (либо правое значение, такое как безымянный временный объект, или значение-x, такое как результат std::move), и выбирает оператор копирования присваивания, если аргумент является ссылкой на левое значение (имя объекта или функция/оператор, возвращающие ссылку на левое значение). Если предоставлен только оператор копирования присваивания, все категории аргументов выбирают его (поскольку он принимает свой аргумент по значению или как ссылку на const, поскольку правые значения могут связываться с константными ссылками), что делает оператор копирования присваивания резервным для оператора перемещения присваивания, когда оператор перемещения недоступен.
Не определено, будут ли виртуальные базовые подобъекты, доступные через более чем один путь в решетке наследования, присваиваться более одного раза оператором копирующего присваивания по умолчанию (то же самое относится к оператору перемещения присваивания).
См. перегрузку оператора присваивания для получения дополнительных сведений о предполагаемом поведении оператора копирующего присваивания, определённого пользователем.
Пример
#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
struct A
{
int n;
std::string s1;
A() = default;
A(A const&) = default;
// user-defined copy assignment (copy-and-swap idiom)
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;
// implicitly-defined copy assignment
};
struct C
{
std::unique_ptr<int[]> data;
std::size_t size;
// user-defined copy assignment (non copy-and-swap idiom)
// note: copy-and-swap would always reallocate resources
C& operator=(const C& other)
{
if (this != &other) // not a self-assignment
{
if (size != other.size) // resource cannot be reused
{
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; // user-defined copy assignment
B b1, b2;
b2.s1 = "foo";
b2.s2 = "bar";
std::cout << "b1 = b2 calls ";
b1 = b2; // implicitly-defined copy assignment
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 абстрактен и имеет некопируемые виртуальные базовые классы | в этом случае оператор определяется как удалённый |
См. также
- конвертирующий конструктор
- конструктор копирования
- исключение копирования
- конструктор по умолчанию
- деструктор
-
explicit - инициализация
- перемещение присваивания
- конструктор перемещения
-
new
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/as_operator