左值和右值概述
什么是左值?什么是左值引用?
左值是一个表示数据的表达式(如变量名或解引用的指针),我们**可以获取它的地址并且可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。**定义时const
修饰符后的左值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名。
什么是右值?什么是右值引用? 右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。右值引用就是对右值的引用,给右值取别名。
右值引用:
代码语言:javascript复制int main()
{
int x = 1, y = 2;
int&& ret1 = (x y);
string&& ret2 = string("111");
string&& ret3 = to_string(123);
return 0;
}
左值引用不能给右值引用取别名,但是const
左值引用可以。右值引用不能给左值取别名,但是可以给move
以后的左值取别名。
int main()
{
const string& ret1 = string("1111");
const int& ret2 = 10;
string s1("2222");
string&& ret3 = move(s1);
}
左右值意义及使用场景
引用的意义是减少拷贝提高效率。
左值引用的使用场景: 做参数和做返回值都可以提高效率
代码语言:javascript复制void func1(gwj::string s)
{}
void func2(const gwj::string& s)
{}
int main()
{
gwj::string s1("hello world");
// func1和func2的调用我们可以看到左值引用做参数减少了拷贝,提高效率的使用场景和价值
func1(s1);
func2(s1);
// string operator =(char ch) 传值返回存在深拷贝
// string& operator =(char ch) 传左值引用没有拷贝提高了效率
s1 = '!';
return 0;
}
左值引用的短板: 但是当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回,只能传值返回。例如:·gwj::string to_string(int value)·函数中可以看到,这里只能使用传值返回,传值返回会导致至少1次拷贝构造(如果是一些旧一点的编译器可能是两次拷贝构造)。
移动构造
代码语言:javascript复制// 移动构造
string(string && s)
:_str(nullptr)
, _size(0)
, _capacity(0)
{
cout << "string(string&& s) -- 移动语义" << endl;
swap(s);
}
// 移动赋值
string& operator=(string && s)
{
cout << "string& operator=(string&& s) -- 移动语义" << endl;
swap(s);
return *this;
}
左值进行深拷贝,右值进行移动构造
在使用移动构造后,不再需要创建一个临时变量,直接将资源进行转移,不需要执行拷贝构造,大大提高效率
代码语言:javascript复制namespace gwj
{
class string
{
public:
typedef char* iterator;
iterator begin()
{
return _str;
}
iterator end()
{
return _str _size;
}
string(const char* str = "")
:_size(strlen(str))
, _capacity(_size)
{
//cout << "string(char* str)" << endl;
_str = new char[_capacity 1];
strcpy(_str, str);
}
// s1.swap(s2)
void swap(string& s)
{
::swap(_str, s._str);
::swap(_size, s._size);
::swap(_capacity, s._capacity);
}
// 拷贝构造
string(const string& s)
:_str(nullptr)
{
cout << "string(const string& s) -- 深拷贝" << endl;
string tmp(s._str);
swap(tmp);
}
// 赋值重载
string& operator=(const string& s)
{
cout << "string& operator=(string s) -- 深拷贝" << endl;
string tmp(s);
swap(tmp);
return *this;
}
// 移动构造
string(string && s)
:_str(nullptr)
, _size(0)
, _capacity(0)
{
cout << "string(string&& s) -- 移动语义" << endl;
swap(s);
}
// 移动赋值
string& operator=(string && s)
{
cout << "string& operator=(string&& s) -- 移动语义" << endl;
swap(s);
return *this;
}
~string()
{
delete[] _str;
_str = nullptr;
}
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
void reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
void push_back(char ch)
{
if (_size >= _capacity)
{
size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
reserve(newcapacity);
}_str[_size] = ch;
_size;
_str[_size] = '