Copy assignment operator
复制赋值算子
类的副本赋值算子T
是一个具有名称的非模板非静态成员函数。operator=
它只需要一个类型的参数。T
,,,T&
,,,const T&
,,,volatile T&
,或const volatile T&
.对一种类型的人来说CopyAssignable
,它必须有一个公共副本赋值操作符。
句法
class_name & class_name :: operator= ( class_name ) | (1) | |
---|---|---|
class_name & class_name :: operator= ( const class_name & ) | (2) | |
class_name & class_name :: operator= ( const class_name & ) = default; | (3) | (since C++11) |
class_name & class_name :: operator= ( const class_name & ) = delete; | (4) | (since C++11) |
解释
- 时,复制赋值操作符的典型声明抄袭互换成语可以使用。
- 当复制和交换成语不能使用%28不可交换类型或性能降低时,复制赋值操作符的典型声明。
- 强制编译器生成副本赋值运算符。
- 避免隐式复制分配。
只要被选中,就会调用副本赋值运算符。过载分辨率例如,当对象出现在赋值表达式的左侧时。
隐式声明副本赋值操作符
如果没有为类类型%28提供用户定义的副本分配操作符struct
,,,class
,或union
%29,编译器将始终将其声明为类的内联公共成员。这个隐式声明的副本赋值操作符具有以下形式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&)
.%28注意,由于这些规则,隐式声明的副本赋值运算符不能绑定到易失性的lvalue参数。%29。
一个类可以有多个副本赋值操作符,例如两个T& T::operator=(const T&)
和T& T::operator=(T)
如果存在某些用户定义的副本赋值操作符,则用户仍然可以强制生成带有关键字的隐式声明的副本赋值操作符。default
.%28自C++11%29。
隐式声明的%28或默认的第一次声明%29复制赋值操作符有一个异常规范,如动态异常规范%28直到C++17%29异常规格%28自C++17%29。
因为总是为任何类声明副本赋值运算符,所以基类赋值运算符总是隐藏的。如果使用-声明用于从基类中引入赋值操作符,其参数类型可以与派生类的隐赋值运算符的参数类型相同,使用声明也被隐式声明隐藏。
隐式删除-声明的副本赋值操作符
类的隐式声明副本赋值操作符。T
定义为删除
如果下列任何一项都是正确的:
T
具有用户声明的移动构造函数;
T
有一个用户声明的移动赋值操作符。
否则,它被定义为默认的。
类的默认副本赋值操作符T
定义为删除
如果下列任何一项都是正确的:
T
具有非类类型的非静态数据成员%28或其数组%29,即const
;
T
具有引用类型的非静态数据成员;
T
具有不能为副本分配失败的非静态数据成员或直接或虚拟基类分配%28重载解析的直接或虚拟基类,或选择已删除或不可访问的函数%29;
T
是工会式课程,并且有一个变体成员,其相应的赋值运算符是非平凡的。
平凡拷贝赋值算子
类的副本赋值操作符T
如果以下所有内容都为真,则是微不足道的:
- 它不是用户提供的%28含义,它是隐式定义的或默认的%29,如果它是默认的,它的签名与隐式定义的%28相同,直到C++14%29;
T
没有虚拟成员功能;
T
没有虚拟基类;
- 的每个直接基所选择的副本赋值运算符。
T
是微不足道的;
- 为每个非静态类类型%28或类类型%29成员的数组选择的复制赋值运算符。
T
是微不足道的;
T has no non-static data members of volatile-qualified type. | (since C++14) |
---|
T
的非静态数据成员。易挥发-合格类型。
%28自C++14%29
一个简单的副本赋值操作符将对象表示的副本作为std::memmove
所有与C语言%28POD类型%29兼容的数据类型都是微不足道的可复制的可分配的。
隐式定义的拷贝赋值操作符
如果隐式声明的副本赋值运算符既不删除也不平凡,则定义为%28,即编译器生成和编译函数体%29ODR-使用.为union
类型时,隐式定义的副本赋值将对象表示形式%28的std::memmove
29%。对于非工会类类型%28class
和struct
%29,运算符按照初始化顺序对对象%27s基和非静态成员执行成员级副本分配,使用标量内建赋值和类类型的复制分配运算符。
隐式定义的副本赋值操作符的生成不推荐%28,因为C++11%29如果T
具有用户声明的析构函数或用户声明的复制构造函数。
注记
如果同时提供了复制和移动赋值运算符,则如果参数为r值
%28或aprvalue
例如无名的临时的或x值
如…的结果std::move
%29,如果参数是洛值
%28命名对象或返回lvalue引用%29的函数/运算符。如果只提供副本分配,则所有参数类别都选择它%28,只要它按值或作为对Const的引用,因为rvalue可以绑定到Const引用%29,这使得在移动不可用时,复制分配成为移动分配的后盾。
未指定可通过继承格中的多条路径访问的虚拟基类次对象是否由隐式定义的副本赋值操作符%28同样分配给多个移动分配29%。
见赋值操作符过载有关用户定义的复制赋值操作符的预期行为的其他详细信息。
例
二次
#include <iostream>
#include <memory>
#include <string>
#include <algorithm>
struct A
{
int n;
std::string s1;
// user-defined copy assignment, copy-and-swap form
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;
// non-copy-and-swap assignment
C& operator=(const C& other)
{
// check for self-assignment
if(&other == this)
return *this;
// reuse storage when possible
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;
}
// note: copy-and-swap would always cause a reallocation
};
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 | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 2171 | C++14 | operator=(X&) = default was non-trivial | made trivial |
© cppreference.com
在CreativeCommonsAttribution下授权-ShareAlike未移植许可v3.0。