语义相关
值语义
指目标对象由源对象拷贝生成,且生成后与源对象完全无关,彼此独立存在,改变互不影响,就像int类型互相拷贝一样。C++的内置类型(bool/int/double/char)都是值语义,标准库里的complex<> 、pair<>、vector<>、map<>、string等等类型也都是值语意,拷贝之后就与原对象脱离关系。C++中基于值语义的拷贝构造和赋值拷贝,会招致对资源密集型对象不必要拷贝,大量的拷贝很可能成为程序的性能瓶颈。
对象语义
对象语义就是只有一个对象,不支持拷贝复制等操作。
常用手段
- 将拷贝构造函数或者赋值运算符函数=delete
- 将拷贝构造函数或者赋值运算符函数设置为私有的
- 可以使用继承的思想,将基类拷贝构造函数与赋值运算符函数删除(设为私有),让派生类继承基类
移动语义
- 左值引用,使用T&,只能绑定左值
- 右值引用,使用T&&,只能绑定右值
- 常量左值引用,使用const T&,既可以绑定左值,又可以绑定右值,但是不能对其进行修改
移动语义不是试图取代复制语义,也不是以任何方式破坏它。相反,该提议旨在增强复制语义。
移动语义主要是性能优化:将昂贵的对象从内存中的一个地址移动到另外一个地址的能力,同时窃取源资源以便以最小的代价构建目标。
在C++11之前,当进行值传递时,编译器会隐式调用拷贝构造函数;自C++11起,通过右值引用来避免由于拷贝调用而导致的性能损失。
右值引用的主要用途是创建移动构造函数和移动赋值运算符
。移动构造函数可以避免内存重新分配,这是因为移动构造函数的参数是一个右值引用,也可以说是一个临时对象
,而临时对象在调用之后就被销毁不再被使用,因此,在移动构造函数中对参数进行移动而不是拷贝。换句话说,右值引用和移动语义允许我们在使用临时对象时避免不必要的拷贝。
// 移动构造函数
String(String &&rhs)
: _pstr(rhs._pstr)
{
rhs._pstr = nullptr;
}
// 移动赋值运算符函数
String& operator=(String&& rhs)
{
if(this != rhs)
{
delete [] _pstr; // 释放左操作数
_pstr = rhs._pstr; // “移动”所有权
rhs._pstr = nullptr; // 避免临时对象的析构函数将资源释放掉
}
return *this;
}