1、拷贝构造函数的基本概念:
如果构造函数的第一个参数是自身类类型的引用,且其他所有参数(如果有的话)都有默认值,则此构造函数是拷贝构造函数。
使用情况:
拷贝初始化(用=定义变量)、其他拷贝初始化的情况(将一个对象作为实参传递给一个非引用类型的形参、从一个返回类型为非引用类型的函数返回一个对象、用花括号列表初始化一个数组中的元素或一个聚合类中的成员、初始化标准库容器或是调用其insert或push成员)
2、拷贝赋值运算符:
拷贝赋值运算符本身是一个重载的赋值运算符,定义为类的成员函数,左侧运算对象绑定到隐含的this参数,而右侧运算对象是所属类类型的,作为函数的参数,函数返回指向其左侧运算对象的引用。
使用:当对类对象进行赋值时,会使用拷贝赋值运算符。
合成拷贝赋值运算符的任务:将右侧对象的非static成员逐个赋予左侧对象的对应成员,这些赋值操作是由成员类型的拷贝赋值运算符来完成的。
若一个类未定义自己的拷贝赋值运算符,编译器就会为其合成拷贝赋值运算符,完成赋值操作,但对于某些类,还会起到禁止该类型对象赋值的效果。
3、析构函数:
释放对象使用的资源,销毁非静态数据成员。从语法上看,它是类的一个成员函数,名字是波浪号接类名,没有返回值,也不接受参数。
合成析构函数体为空,但这并不意味着它什么也不做,当空函数体执行完后,非静态数据成员会被逐个销毁。即,成员是在析构函数体之后隐含的析构阶段中进行销毁的。
#include<iostream>
#include<vector>
using namespace std;
struct X
{
X() { cout << "构造函数X()" << endl; }
X(const X&) { cout << "拷贝构造函数X(const X&)" << endl;}
X& operator = (const X &rhs)
{
cout <<"拷贝赋值运算符=(const X&)" << endl;
return *this;
}
~X() { cout << "析构函数 ~X()" << endl;}
};
void f1(X x)
{
}
void f2(X &x)
{
}
int main()
{
cout << "局部变量:" << endl;
X x;
cout << endl;
cout << "非引用参数传递:" << endl;
f1(x);
cout << endl;
cout << "引用参数传递:" << endl;
f2(x);
cout << endl;
cout << "动态分配:" << endl;
X *px = new X;
cout << endl;
cout << "添加到容器中:" << endl;
vector<X> vx;
vx.push_back(x);
cout << endl;
cout << "释放动态分配对象:" << endl;
delete px;
cout << endl;
cout << "间接初始化和赋值:" << endl;
X y = x;
y = x;
cout << endl;
cout << "程序结束:" << endl;
return 0;
}
4、使用default与阻止拷贝
通过将拷贝控制成员定义为=default来显式地要求编译器生成合成的版本,合成的函数将隐式地声明为内联的。
将拷贝构造函数和拷贝赋值运算符定义为删除的函数来阻止拷贝。
对于析构函数已经删除的类型,不能定义该类型的变量或释放指向该类型动态分配对象的指针。
本质上,当不可能拷贝、赋值或销毁类的成员时,类的合成拷贝控制成员就被定义为删除的。
5、交换操作
6、对象移动
标准库容器、sring和shared_ptr类既支持移动也支持拷贝。IO类和unique_ptr类可以移动但不能拷贝。
右值引用:必须绑定到右值的引用,&&,右值引用只能绑定到一个将要销毁的对象上,因此可以自由的移动其资源。
左值引用:常规引用,不能绑定到要 转换的表达式、字面常量或返回右值的表达式。而右值引用恰好相反,可以绑定到这类表达式,但不能绑定到一个左值上。
返回左值的:返回左值引用的函数及赋值、下标、解引用和前置递增/递减运算符。
左值持久,右值短暂。
返回右值的:返回非引用类型的函数及算术、关系、位和后置递增/递减运算符。