左值与右值的区别
- 左值持久,右值短暂(右值要么是字面值常量,要么是表达式求值过程中创建的临时变量)
- 左值是变量,右值不能被赋值
左值引用与右值引用
- 右值引用是为了支持移动操作,通过&&来获得右值引用
- 左值引用是相对于右值引用的,通过&来获得
int i = 42;
int &r = i; //正确,r引用i
int &&rr = i; //错误,不能将一个右值绑定到一个左值(变量)上
int &r2 = i*42; //错误,不能将一个左值绑定到一个右值上
const int &r3 = i*42; //正确,可以将一个const的引用绑定到一个右值上
int &&rr2 = i*42; //正确,将rr2绑定到一个乘法结果上
int &&rr2 = 42; //正确,字面值常量是一个右值
标准库move函数
显示的将一个左值转换为对应的右值引用类型;我们可以销毁一个移后源对象,也可以赋予它新值,但不能使用一个移后源对象的值。
#include <iostream>
#include <utility>
#include <vector>
#include <string>
int main()
{
std::string str = "Hello";
std::vector<std::string> v;
// uses the push_back(const T&) overload, which means
// we'll incur the cost of copying str
v.push_back(str);
std::cout << "After copy, str is \"" << str << "\"\n";
// uses the rvalue reference push_back(T&&) overload,
// which means no strings will be copied; instead, the contents
// of str will be moved into the vector. This is less
// expensive, but also means str might now be empty.
v.push_back(std::move(str));
std::cout << "After move, str is \"" << str << "\"\n";
std::cout << "The contents of the vector are \"" << v[0]
<< "\", \"" << v[1] << "\"\n";
}
Possible output:
After copy, str is "Hello"
After move, str is ""
The contents of the vector are "Hello", "Hello"
注意:如果没有自已定义移动构造函数,使用std::move()会默认调用拷贝构造函数。
拷贝构造函数与移动构造函数的区别:
- 拷贝构造函数的形参是一个左值引用,而移动构造函数的形参是一个右值引用
- 拷贝构造函数完成的是整个对象或变量的拷贝,而移动构造函数是生成一个指针指向源对象或变量的地址,接管源对象的内存,相对于大量数据的拷贝节省时间和内存空间。
#include <iostream>
#include <string>
#include <map>
#include <set>
#include <vector>
class Book
{
public:
Book()
{
this->_bookname = " ";
std::cout << "call default construct function" << std::endl;
}
Book(std::string bookname) :_bookname(bookname)
{
std::cout << "call construct function:"<<_bookname << std::endl;
}
//拷贝构造函数
Book(const Book& book)
{
this->_bookname = book._bookname;
std::cout << "call copy construct function:"<<_bookname << std::endl;
}
//移动构造函数
Book(const Book&& book)
{
this->_bookname = book._bookname;
std::cout << "call move construct function:"<<_bookname << std::endl;
}
bool operator < (const Book& book)const
{
if (this->_bookname < book._bookname)
return true;
return false;
}
~Book()
{
std::cout << "call destruct function" << _bookname << std::endl << std::endl;
}
private:
std::string _bookname;
};
int main()
{
//std::set<Book> bookset;
//std::cout << "test bookset insert:" << std::endl;
//bookset.insert(Book("Linux"));
//std::cout << "test bookset emplace:" << std::endl;
//bookset.emplace("C++");
//std::cout << std::endl;
for (auto& it : bookset)
{
std::cout << it._bookname << std::endl;
}
//std::map<int,Book> bookmap;
//std::cout << "test bookmap insert:" << std::endl;
//bookmap.insert(std::make_pair(1,"Mysql"));
//std::cout << "test bookmap emplace:" << std::endl;
//bookmap.emplace(std::make_pair(2,"Python"));
//std::cout << std::endl;
std::vector<Book> bookvec;
long long t = clock();
std::cout << "test bookvec push_back:" << std::endl;
bookvec.push_back(Book("Go"));
long long t1 = clock();
std::cout <<"time:"<< t1 - t << std::endl;
std::cout << "test bookvec emplace:" << std::endl;
bookvec.emplace_back(Book("Jave"));
long long t2 = clock();
std::cout << "time:" << t2 - t1 << std::endl;
system("pause");
return 0;
}