这里的内容注意参考书籍《深入应用C++11代码优化与工程级应用》
今天,重温一下右值。
使用右值,使得我们的C++程序更加高效。
我们可以简单把右值理解为一个临时变量。之前,我们谁也不会在意这个临时变量,但要付出了效率的代价。
而右值引用就是对右值进行的引用类型,与我们通常所说的引用一样,一定要记得初始化。
左右值区分:
void func(X& x); // 左值引用 重载
void func(X&& x); // 右值引用 重载
X x;
X foobar();
func(x); // 参数为左值,调用func(X& x);
func(foobar()); // 参数为右值,调用func(X&& x);
再看看这个:
// lvalues:
//
int i = 42;
i = 43; // ok, i is an lvalue
int* p = &i; // ok, i is an lvalue
int& foo();
foo() = 42; // ok, foo() is an lvalue
int* p1 = &foo(); // ok, foo() is an lvalue
// rvalues:
//
int foobar();
int j = 0;
j = foobar(); // ok, foobar() is an rvalue
int* p2 = &foobar(); // error, cannot take the address of an rvalue
j = 42; // ok, 42 is an rvalue
之前在初始化列表的博客中提到过,使用初始化列表进行初始化,比在构造函数中初始化效率更高,道理是一样的。
这结论一定是正确的,当你用VS编译器试图写代码进行验证的时候,你也许就会骂娘了,这他妈输出结果不是一样的吗。
我只能呵呵了,因为编译器对程序进行了优化,你是看不到的。如果非要搞明白,就试图一步一步看看反汇编吧,包你满意。
下面就说说使用右值如何避免深拷贝。
此时,你可能又要犯嘀咕了?
深拷贝不是好事儿吗,使我们自己写的赋值构造函数实现深拷贝吗,是为了避免两个指针指向同一个东西,也避免删除同一个东西两次。
但,凡是都是在不停的发展的。因为C++11引入了右值概念,所以这就使得之前我们所写的赋值构造函数并不是那么完美了。主要还是效率的问题了。
下面就是用到了移动构造函数~之前也有提到过啊:
MyString(MyString&& str) {
std::cout <<"Move Constructor is called! source: "<< str._data << std::endl;
_len = str._len;
_data = str._data; // 避免了不必要的拷贝
str._len = 0;
str._data = NULL;
}
MyString&operator=(MyString&& str) {
std::cout <<"Move Assignment is called! source: "<< str._data << std::endl;
if (this != &str) {
_len = str._len;
_data = str._data; // 避免了不必要的拷贝
str._len = 0;
str._data = NULL;
}
return *this;
}
有了右值引用和移动语义,在设计和实现类时,对于需要动态申请大量资源的类,应该设计右值引用的拷贝构造函数和赋值函数,以提高应用程序的效率。需要注意的是,我们一般在提供右值引用的构造函数的同时,也会提供常量左值引用的拷贝构造函数,以保证移动不成还可以使用拷贝构造。
C++11新特性应用--让你的程序更高效(右值引用避免深拷贝)
原文:http://blog.csdn.net/wangshubo1989/article/details/50479162