C++11:右值引用和转移赋值
2020-06-20 本文已影响0人
行走的代码
1.首先认识左值和右值的定义:
左值:表达式可以引用到一个对象,并且这个对象是一块内存空间并可以检测和存储,这个表示即是左值。
右值:直接引用了一个存储在内存地址中的数据。
右值最大限度只能被一个常量引用:
1
const int &a = 1;
规则:临时变量是右值,且可以改变:
1
T().set().get()
T为临时变量,set()设置新值,get()获取更改后的值。
2.首先写一个MyString类:
#include<vector>
class MyString
{
private:
int _len;
char* _data;
void init_data(const char* str)
{
_data = new char[_len+1];
memcpy(_data,str,_len);
_data[_len] = '\0';
}
public:
MyString()
{
_len = 0;
_data = NULL;
}
MyString(const char* str)
{
_len = strlen(str);
init_data(str);
}
MyString(const MyString& rhs)
{
_len = rhs._len;
init_data(rhs._data);
}
MyString& operator=(MyString& rhs)
{
if(this != &rhs)
{
_len = rhs._len;
init_data(rhs._data);
//MyString(rhs);
}
return *this;
}
virtual ~MyString()
{
if(_data) free(_data);
}
};
int main()
{
Mystring a;
a = MyString("Hello");
std::vector<MyString> vec;
vec.push_back(MyString("World"));
}
左值和右值引用符号区别:
void print_value(int& a)
{
std::cout << "LValue" << endl;
}
void print_value(int&& a)
{
std::cout << "RValue" << endl;
}
右值引用实际是用来支持转移赋值和转移构造:
MyString(MyString&& rhs) //不包含const
{
_len = rhs._len;
_data = rhs._data;
rhs._len = 0;
rhs._data = NULL;
}
MyString& operator(MyString&& rhs) //不包含 const
{
if(this != &rhs)
{
_len = rhs._len;
_data = rhs._data;
rhs._len = 0;
rhs._data = NULL;
}
return *this;
}
转移构造和赋值的好处是:节省了资源,提高了程序效率。
std::move是标准库提供的将一个命名对象转换为一个临时对象(右值)来支持转移构造和赋值:
template <class T> void swap(T& a, T& b)
{
T c(std::move(a));
a=std::move(b);
b=std::move(c);
}
template <class T, size_t N> void swap(T (&a)[N], T(&b)[N])
{
for(size_t i = 0; i<N; ++i) swap(a[i], b[i]);
}
这样提高了swap效率。
未显式定义转移构造函数和转移赋值函数,会使用默认的。但有几种情况需要显式定义:
- 成员中含有裸指针,用默认的存在释放问题;
- 自定义了构造函数和赋值函数,那么需要显式定义move的方法;
-
显式定义析构函数,需要显式定义move方法;
v2-c05999fd24c153670011c7eb161a7d8a_720w.jpg