赞
踩
左值与右值(lvalue/rvalue)这两概念是从 c 中传承而来的。
在 c 中,左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式)。
右值指的则是只能出现在等号右边的变量(或表达式)。
右值不能当成左值使用,但左值可以当成右值使用。
C++中其实是左值表达式与右值表达式。其中:表达式是有值的,值是有类型的,值是动态的,类型是静态的。例如:
int &a = b; a 是一个左值,他的类型是左值引用,指向一个左值。
int &&c = fun(); c是一个左值,他的类型是右值引用,指向一个右值。
如果一个函数的返回类型是左值引用,那么调用这个函数得到的返回值将是一个 lvalue[N3690,3.10.1],之所以特别地说这个事,是因为如果一个函数的返回值不是引用类型,那调用这个函数得到的结果将是一个临时变量,是个右值,而且是纯右值(prvalue)
下图运算操作所产生的中间结果是右值;
但是string类型却是可以的。这是C++相较C独有的。因为string 不是基础类型而是一个类,其实只是调用了成员函数”operator=“。
定义如下:
对于基础类型,右值是不可被修改的,也不可被 const, volatile 所修饰
对于自定义的类型,右值却允许通过它的成员函数进行修改。
其实就是:右值调用成员函数是被允许的,但成员函数有可能不是 const 类型,因此通过调用右值的成员函数,也就可能会修改了该右值。不知道是不是设计初衷。//疑问点
引入右值引用之前:引用只能指向左值,常量引用可以指向右值和左值,这就导致没有专门为右值做的引用。即下图对比:(右值可以被const 的引用指向,而不可以被引用指向。)
这样就可以用一个基类的引用指向一个子类的临时变量,然后通过这个引用来实现多态,但又不用处理子类的销毁。
class Base { public: virtual void print() const{ cout << "base print()" << endl; } }; class DerOne: public Base { public: virtual void print() const { cout << "DerOne print()" << endl; } }; class DerTwo: public Base { public: virtual void print() const { cout << "DerTwo print()" << endl; } }; Base GetBase() { return Base(); } DerOne GetDerOne() { return DerOne(); } DerTwo GetDerTwo() { return DerTwo(); } int main() { const Base& ref1 = GetBase(); const Base& ref2 = GetDerOne(); const Base& ref3 = GetDerTwo(); ref1.print(); ref2.print(); ref3.print(); return 0; }
实现效果如下:
注意:const 对象只能调用const 成员函数。
自从C++ 11 引入右值引用以后,以前的引用就称之为左值引用。
int &a = b; a 是一个左值,他的类型是左值引用,指向一个左值。
int &&c = fun(); c是一个左值,他的类型是右值引用,指向一个右值。
为了解决一系列的问题C++ 11引入了右值引用,用&&表示。从而引入了move(), forward() 等。
目的有两个:
一个是为自定义类型实现 move 语义;一个是配合 forwarding reference 来实现完美转发。
移动语义可以减少无谓的内存拷贝,要想实现移动语义,需要实现移动构造函数和移动赋值函数。
- std::move()将一个左值转换成一个右值,强制使用移动拷贝和赋值函数,这个函数本身并没有对这个左值什么特殊操作。
- std::forward()和universal references通用引用共同实现完美转发。
- 用empalce_back()替换push_back()增加性能。
- std::move() 的主要作用是将一个左值转为 xvalue, 它的实现,本质上就是一个 static_cast<>。
- 而 std::forward() 则是用来配合 forwarding reference 实现完美转发,它主要的作用是将一个类型为引用(左值引用或右值引用)的左值(引用这个变量本身),转化为它的类型所对应的值类型
std::string foo = "foo-string";
std::string bar = "bar-string";
std::vector<std::string> myvector;
myvector.push_back(foo); // copies
myvector.push_back(std::move(bar)); // moves
std::cout << "myvector contains:";
for (std::string& x : myvector) std::cout << ' ' << x;
std::cout << '\n';
cout << foo << endl;
cout << bar << endl;
bar
中的便来给你已经被让渡到vector
中去了move 兼顾了深拷贝与浅拷贝的优点;
带move 的是调用了移动构造、移动赋值运算符
String s1("Hello"); // 构造函数
cout << s1 << endl;
String s2 = s1; // 调用拷贝构造函数
String s2(s1); // 调用拷贝构造函数
cout << s2 << endl;
String s2A(std::move(s1)); // 移动构造函数
cout << s2A << endl;
String s3; // 无参构造函数
cout << s3 << endl;
s3 = s2; // 调用赋值函数
cout << s3 << endl;
String s3A; // 无参构造函数
s3A = std::move(s2A); // 移动赋值运算符
cout << s3A << endl;
- delete 自己的堆空间;(构造的话,本身不存在数据,少了一步delete)
- 将指针指向需要的空间中的地址块;
- 将对方的指针指向NULL;
// 移动构造函数 String::String(String&& other) { if (other.m_data != NULL) { // 资源让渡 m_data = other.m_data; other.m_data = NULL; } } // 移动赋值运算符 String& String::operator=(String&& rhs)noexcept { if(this != &rhs) { delete[] m_data; m_data = rhs.m_data; rhs.m_data = NULL; } return *this; }
int main() { // foo bar p // --- --- --- std::unique_ptr<int> foo; // null std::unique_ptr<int> bar; // null null int* p = nullptr; // null null null foo = std::unique_ptr<int>(new int(10)); // (10) null null bar = std::move(foo); // null (10) null p = bar.get(); // null (10) (10) *p = 20; // null (20) (20) p = nullptr; // null (20) null foo = std::unique_ptr<int>(new int(30)); // (30) (20) null p = foo.release(); // null (20) (30) *p = 40; // null (20) (40) std::cout << "foo: "; if (foo) std::cout << *foo << '\n'; else std::cout << "(null)\n"; std::cout << "bar: "; if (bar) std::cout << *bar << '\n'; else std::cout << "(null)\n"; std::cout << "p: "; if (p) std::cout << *p << '\n'; else std::cout << "(null)\n"; std::cout << '\n'; delete p; // the program is now responsible of deleting the object pointed to by p // bar deletes its managed object automatically return 0; }
unique_ptr<string> p0;
{
unique_ptr<string> p1(new string());
p0 = std::move(p1);
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。