拷贝控制

1. 拷贝函数

Example(const Example&);
Example& operator=(const Example&);

2. 阻止拷贝

  有些类不允许拷贝,比如iostream类和unique_ptr智能指针。阻止拷贝通过拷贝函数实现。有下面3种方法:

1. 定义删除的拷贝函数

  有些类不能有拷贝构造函数、拷贝赋值函数,比如互斥锁。

class Example {
public:	
	// 构造函数。
	Example() = default;
	// 定义删除的拷贝构造函数和拷贝赋值函数。
	Example(const Example&) = delete;
	Example& operator=(const Example&) = delete;
}

2. 声明拷贝函数为private的,且不定义它们

  C++旧标准不支持定义删除的函数时,通过这种方法阻止拷贝。

class Example {
	Example(const Example&);	
	Example& operator=(const Example&);
public:
	// 构造函数。
	Example() = default;
}

  只声明不定义,使得成员函数或友元函数也不能调用拷贝函数,否则会出现链接错误。

3. 编译器合成删除的默认函数

  默认函数:如果用户不自定义,编译器会自动合成默认构造函数、默认拷贝函数、默认移动函数、默认析构函数。
  编译器合成删除的函数的情况如下:

  1. 如果某个成员的析构函数不可访问,则编译器合成的析构函数是删除的。
  2. 如果某个成员的拷贝构造函数 / 析构函数不可访问,则编译器合成的拷贝构造函数是删除的。
  3. 如果某个成员是const / 引用 / 拷贝赋值函数不可访问,则编译器合成的拷贝赋值函数是删除的。
  4. 如果某个成员是const且无类内初始化且未显式定义默认构造函数 / 引用且无类内初始化 / 析构函数不可访问,则编译器合成的默认构造函数是删除的。

  不可访问指函数是私有的或删除的。成员指数据成员、类成员、基类。

3. 对象移动

1. 右值引用

  右值要么是字面常量,要么是在表达式求值过程中创建的临时对象。
  右值引用就是必须绑定到右值的引用。

2. std::move函数

  std::move将一个左值转换为对应的右值引用类型。它的实现:

template <typename T>
typename remove_reference<T>::type&& move(T&& t) {
	return static_cast<typename remove_reference<T>::type&&>(t);

  也就是说std::move是用static_cast实现的。下面两行等价:

int&& r = move(1);
int&& r = static_cast<int&&>(1);

3. 参数匹配

void fun(int&); // 函数1。
void fun(int&&); // 函数2。
void fun(const int&); // 函数3。
void fun(const int&&); // 函数4。

  字面值常量的匹配顺序:2、4、3。
  变量(普通变量、左值引用变量、右值引用变量)的匹配顺序:1、3。
  std::move(变量或字面值常量)的匹配顺序:2、4、3。

  常量(普通常量、左值引用常量、右值引用常量)的匹配顺序:3。
  std::move(常量)的匹配顺序:4、3。

4. 对象移动

  移动函数与拷贝函数的声明区别:移动函数的参数是非const类型的右值引用;拷贝函数的参数是const类型的左值引用。

Example(Example&&);
Example& operator=(Example&&);

  由参数匹配知,使用std::move时,会优先匹配移动函数,没有移动函数时会匹配形参为const类型的拷贝函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值