11 移动语义和智能指针
11.1移动语义
左值和右值
右值:不能取地址;
右值包括临时对象(string(“world”)
),临时变量,字面值常量10
;
临时对象会短暂存在栈上,不会持续很久;
”world”
:字符串常量位于文字常量区,可以取地址,不是字面值常量?
string s3 = “world”;//分为两步
string(const char*) ;
string(const String&);//string(“world”)//右值;
文字常量区:全局const
变量、字符串常量;局部的const位于栈区
左值:可以取地址;可以绑定左值,识别左值,不可以绑定右值;
int &ref = a;
int &ref = 10;//error,不可以绑右值
const
左值引用:可以绑定到右值,但是同时可以绑定到左值,无法区分左值右值;
const int &ref = a;
const int &ref = 10;//可以绑右值
右值引用
右值引用:&& ;可以识别右值,右值引用本身是左值,可以取地址;但是右值引用可能是右值(函数的返回参数是右值引用的情况);
总结:函数的参数一定是左值
int &&func() { }//这里的func是右值
移动构造函数
String(String &&rhs)
: _pstr(rhs._pstr)
{
cout << "String(String &&)" << endl;
rhs._pstr = nullptr;
}
作用:将申请的堆空间进行转移
注意:针对的是右值,移动构造函数的优先级高于拷贝构造函数
移动赋值运算符
String &operator=(String &&rhs)
{
cout << "String &operator=(String &&)" << endl;
if(this != &rhs)//1、自移动
{
delete [] _pstr;//2、释放左操作数 _pstr = nullptr;
_pstr = rhs._pstr;//3、浅拷贝 rhs._pstr = nullptr;
}
return *this;//4、返回*this }
移动赋值运算符相较于赋值运算符也会优先执行
std::move
作用:将左值转换为右值;内部其实做了强制转换static_cast<T &&>(lvalue)
11.2资源管理
为何需要资源管理:c语言中的打开文件声明的文件指针,在函数多个分支中都需要去写下关闭函数,否则会导致文件指针没有释放,内存泄漏;
C++ RAII 技术
思想:
1、在构造时初始化资源,或者托管资源。
2、析构时释放资源。
3、一般不允许复制或者赋值(值语义-对象语义)。//将拷贝和赋值私有化或者delete
;
4、提供若干访问资源的方法。
本质:本质上就是利用对象的生命周期进行资源管理;类似智能指针,智能指针的雏形;
补充概念:值语义就是可以进行赋值或者复制;对象语义就是不允许;
11.3智能指针
概念:利用对象的生命周期,交由析构函数自动释放new
出来的内存,避免内存泄漏;