拷贝构造函数
如果一个构造函数第一个参数是自身类类型的引用,且任何额外参数都有默认值,则为拷贝构造函数
拷贝初始化发生情况:
- 使用
=
定义变量(如:string nums = "9999"
) - 将一个对象作为实参传递给一个非引用类型的形参
- 从一个返回类型为非引用的类型的函数返回一个对象
- 从花括号列表初始化一个数组中的元素或一个聚合类中的成员
拷贝构造函数自己的参数必须是引用类型否则会递归死循环(https://www.zhihu.com/question/35304261)
拷贝赋值运算符
拷贝赋值运算符是一个名为 operator= 的函数
析构函数
构造函数初始化对象的非static
数据成员;析构函数释放对象使用的资源,并销毁对象的非static
数据成员
什么时候调用析构函数
- 变量在离开作用域时被销毁
- 当一个对象被销毁时,其成员被销毁
- 容器被销毁时,其元素被销毁
delete
时- 对于临时对象,当创建它完整表达式结束时被销毁
三/五法则
需要析构函数的类也需要拷贝和赋值操作
考虑如下代码:
class HasPtr {
public:
HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) { }
~HasPtr() { delete ps;}
private:
std::string *ps;
int i;
};
在上述类中,构造函数中分配的内存将在HasPtr
对象销毁时被释放。不幸的是,上述类中使用了编译器自动合成的拷贝构造函数和拷贝复制运算符。这些函数简单拷贝指针成员,这意味着多个HasPtr
对象可能指向相同的内存:
HasPtr f (HasPtr hp) { // Hasptr是传值参数,所以将被拷贝
Hasptr ret = hp; // 拷贝给定的HasPtr
return ret; // ret和hp被销毁
}
当上述函数f
返回时候,hp
和ret
都被销毁,在两个对象上都会调用HasPtr的析构造函数,此析构函数会delete ret
和hp
中的指针成员。但这两个对象包含相同的指针值,导致double free
;
需要拷贝操作的类也需要赋值操作,反之亦然
使用=default
我们可以通过拷贝控制成员定义为=default
来显示地要求编译器生成合成的版本
阻止拷贝
我们可以通过将拷贝构造函数和拷贝复制运算符定义为删除的函数来组织拷贝。删除的函数是这样一种函数:我们虽然声明了它们,但不能以任何方式使用它们。
析构函数不能是删除的成员
拷贝控制和资源管理
行为像值的类
行为像指针的类
交换操作
- 左值引用:绑定到左值的应用(常规引用)
返回左值引用的函数,连同赋值、下标、解引用和前置递增/递减运算符,都是返回左值表达式的例子。我们可以将一个左值引用绑定到这类表达式的结果上 - 右值引用:必须绑定到右值的引用(只能绑定到一个将要销毁的对象)
返回非引用的函数,连同算数、关系、位以及后置递增/递减运算符,都生成右值。我们不能将一个左值引用绑定到这类表达式上,我们可以将一个const
的左值引用或者一个右值引用绑定到这类表达式上