rvalue references and Move semantics
来源:互联网 发布:最好的门户网站 知乎 编辑:程序博客网 时间:2024/05/16 10:33
【转】http://stackoverflow.com/questions/3106110/can-someone-please-explain-move-semantics-to-me
【another】 Move semantics and rvalue references in C++11
http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html
I find it easiest to understand move semantics with example code. Let's start with a very simple string class which only holds a pointer to a heap-allocated block of memory:
#include <cstring>#include <algorithm>class string{ char* data;public: string(const char* p) { size_t size = strlen(p) + 1; data = new char[size]; memcpy(data, p, size); }
Since we chose to manage the memory ourselves, we need to follow the rule of three. If you don't know what that means, look it up, it is standard C++98 stuff. I am going to defer writing the assignment operator and only implement the destructor and the copy constructor for now:
~string() { delete[] data; } string(const string& that) { size_t size = strlen(that.data) + 1; data = new char[size]; memcpy(data, that.data, size); }
The copy constructor defines what it means to copy string objects. The parameter const string& that
binds to all expressions of type string which allows you to make copies in the following examples:
string a(x); // line 1string b(x + y); // line 2string c(some_function_returning_a_string()); // line 3
Now comes the key insight into move semantics. Note that only in the first line where we copy x
is this deep copy really necessary, because we might want to inspect x
later and would be very surprised if x
had changed somehow. Did you notice how I just said x
three times (four times if you include this sentence) and meant the exact same object every time? We call expressions such as x
"lvalues".
The arguments in lines 2 and 3 are not lvalues, but rvalues, because the underlying string objects have no names, so the client has no way to inspect them again at a later point in time. rvalues denote temporary objects which are destroyed at the next semicolon (to be more precise: at the end of the full-expression that lexically contains the rvalue). This is important because during the initialization of b
and c
, we could do whatever we wanted with the source string, and the client couldn't tell a difference!
C++0x introduces a new mechanism called "rvalue reference" which, among other things, allows us to detect rvalue arguments via function overloading. All we have to do is write a constructor with an rvalue reference parameter. Inside that constructor we can do anything we want with the source, as long as we leave it insome valid state:
string(string&& that) // string&& is an rvalue reference to a string { data = that.data; that.data = 0; }
What have we done here? Instead of deeply copying the heap data, we have just copied the pointer and then set the original pointer to null. In effect, we have "stolen" the data that originally belonged to the source string. Again, the key insight is that under no circumstance could the client detect that the source had been modified. Since we don't really do a copy here, we call this constructor a "move constructor". Its job is to move resources from one object to another instead of copying them.
Congratulations, you now understand the basics of move semantics! Let's continue by implementing the assignment operator. If you're unfamiliar with the copy and swap idiom, learn it and come back, because it's an awesome C++ idiom related to exception safety.
string& operator=(string that) { std::swap(data, that.data); return *this; }};
Huh, that's it? "Where's the rvalue reference?" you might ask. "We don't need it here!" is my answer :)
Note that we pass the parameter that
by value, so that
has to be initialized just like any other string object. Exactly how is that
going to be initialized? In the olden days of C++98, the answer would have been "by the copy constructor". In C++0x, the compiler chooses between the copy constructor and the move constructor based on whether the argument to the assignment operator is an lvalue or an rvalue.
So if you say a = b
, the copy constructor will initialize that
(because the expression b
is an lvalue), and the assignment operator swaps the contents with a freshly created, deep copy. That is the very definition of the copy and swap idiom -- make a copy, swap the contents with the copy, and then get rid of the copy by leaving the scope. Nothing new here.
But if you say a = x + y
, the move constructor will initialize that
(because the expression x + y
is an rvalue), so there is no deep copy involved, only an efficient move. that
is still an independent object from the argument, but its construction was trivial, since the heap data didn't have to be copied, just moved. It wasn't necessary to copy it because x + y
is an rvalue, and again, it is okay to move from string objects denoted by rvalues.
To summarize, the copy constructor makes a deep copy, because the source must remain untouched. The move constructor, on the other hand, can just copy the pointer and then set the pointer in the source to null. It is okay to "nullify" the source object in this manner, because the client has no way of inspecting the object again.
I hope this example got the main point across. There is a lot more to rvalue references and move semantics which I intentionally left out to keep it simple.
- rvalue references and Move semantics
- Move semantics and rvalue references in C++11
- Effective Modern C++ 笔记 第五章:Rvalue References, Move Semantics, and Perfect Forwarding
- 返回局部变量如何避免拷贝:Move semantics and rvalue references in C++11
- C++0x, rvalue reference, move semantics, RVO, NRVO — 我们到底要什么
- C++11中的rvalue references(一):左值和右值(lvalue and rvalue)
- Item25 Use std::move on rvalue reference, std::forward on universal references
- C++ Rvalue References Explained
- C++ Rvalue References Explained
- What is move semantics?
- [C++11] Move Semantics
- Move semantics(C++11)
- c++ move semantics
- Move semantics of RapidJSON
- C++11: Move Semantics (Move Constructor)
- C++11中rvalue references的使用
- lvalue and rvalue distanct
- rvalue and lvalue
- 【奥运美术】“2012(伦敦)奥林匹克美术大会”组委会执行主席董俊新在新闻发布会致辞
- Android RelativeLayout 属性
- 国内网游公司开始纷纷倔起,民族企业成主力军
- 孙鑫VC深入详解教程中ADO访问数据库中出现runtime error的问题解决
- me511完美刷GMS,可以使用android market,同步gmail联系人,使用google导航
- rvalue references and Move semantics
- tree 递归 树形菜单!
- Hibernate开发流程——基本概念和CURD
- 字符驱动相关的重要的数据结构
- Android中的ShapeDrawable的一个注意点
- 三星发布2GHz Cortex-A15 移动芯片Exynos 5250
- jni java调用win32 dll的方法
- SQL Server优化50法(转)
- phpcms 修改$page方法输出样式