这一块主要是讲move语义的,我认为这是在C++0x中,最好的特性之一,因为它几乎可以完全透明的提高效率。
在Stephan T. Lavavej这篇帖子之后,有很多评论,大体上认为C++因为这些特性而变得更复杂了,而难以掌握,另初学者望而生畏。
但是我认为这是值得的,因为C++的宗旨是:“don't pay for what you don't use 不要为你不使用的东西而付出代价”。
由于水平有限,错误之处,请多多指教:
move semantics: the pattern
move语义:模式 
Here's a simple class, remote_integer, that stores a pointer to a dynamically allocated int .  (This is "remote ownership".)  Its default constructor, unary constructor, copy constructor, copy assignment operator, and destructor should all look very familiar to you.  I've additionally given it a move constructor and move assignment operator.  They're guarded by #ifdef MOVABLE so that I can demonstrate what happens with and without them; real code won't do this.
下面是一个简单的类remote_integer, 这个类存储了指向动态分配的int的指针(“远程拥有权”)。你对这个类的默认构造函数,一元构造函数,拷贝构造函数,重载的赋值运算和析构函数都很熟悉。我给它增加了move构造函数和move 赋值运算。它们被#ifdef MOVABLE 保护,所以我可以演示在没有move构造函数和move 赋值运算时会发生什么,真正的代码是没有这个地。
 
  1 //C:\Temp>type remote.cpp
//C:\Temp>type remote.cpp
  2
  3 #include <stddef.h>
#include <stddef.h>
  4
  5 #include <iostream>
#include <iostream>
  6
  7 #include <ostream>
#include <ostream>
  8
  9 using namespace std;
using namespace std;
 10
 11 
 
 12
 13
 class remote_integer
class remote_integer  {
{
 14
 15 public:
public:
 16
 17
 remote_integer()
    remote_integer()  {
{
 18
 19 cout << "Default constructor." << endl;
        cout << "Default constructor." << endl;
 20
 21 
 
 22
 23 m_p = NULL;
        m_p = NULL;
 24
 25 }
    }
 26
 27 
 
 28
 29
 explicit remote_integer(const int n)
    explicit remote_integer(const int n)  {
{
 30
 31 cout << "Unary constructor." << endl;
        cout << "Unary constructor." << endl;
 32
 33 
 
 34
 35 m_p = new int(n);
        m_p = new int(n);
 36
 37 }
    }
 38
 39 
 
 40
 41
 remote_integer(const remote_integer& other)
    remote_integer(const remote_integer& other)  {
{
 42
 43 cout << "Copy constructor." << endl;
        cout << "Copy constructor." << endl;
 44
 45 
 
 46
 47
 if (other.m_p)
        if (other.m_p)  {
{
 48
 49 m_p = new int(*other.m_p);
            m_p = new int(*other.m_p);
 50
 51
 } else
        } else  {
{
 52
 53 m_p = NULL;
            m_p = NULL;
 54
 55 }
        }
 56
 57 }
    }
 58
 59 
 
 60
 61 #ifdef MOVABLE
#ifdef MOVABLE
 62
 63
 remote_integer(remote_integer&& other)
    remote_integer(remote_integer&& other)  {
{
 64
 65 cout << "MOVE CONSTRUCTOR." << endl;
        cout << "MOVE CONSTRUCTOR." << endl;
 66
 67 
 
 68
 69 m_p = other.m_p;
        m_p = other.m_p;
 70
 71 other.m_p = NULL;
        other.m_p = NULL;
 72
 73 }
    }
 74
 75 #endif // #ifdef MOVABLE
#endif // #ifdef MOVABLE
 76
 77 
 
 78
 79
 remote_integer& operator=(const remote_integer& other)
    remote_integer& operator=(const remote_integer& other)  {
{
 80
 81 cout << "Copy assignment operator." << endl;
        cout << "Copy assignment operator." << endl;
 82
 83 
 
 84
 85
 if (this != &other)
        if (this != &other)  {
{
 86
 87 delete m_p;
            delete m_p;
 88
 89 
 
 90
 91
 if (other.m_p)
            if (other.m_p)  {
{
 92
 93 m_p = new int(*other.m_p);
                m_p = new int(*other.m_p);
 94
 95
 } else
            } else  {
{
 96
 97 m_p = NULL;
                m_p = NULL;
 98
 99 }
            }
100
101 }
        }
102
103 
 
104
105 return *this;
        return *this;
106
107 }
    }
108
109 
 
110
111 #ifdef MOVABLE
#ifdef MOVABLE
112
113
 remote_integer& operator=(remote_integer&& other)
    remote_integer& operator=(remote_integer&& other)  {
{
114
115 cout << "MOVE ASSIGNMENT OPERATOR." << endl;
        cout << "MOVE ASSIGNMENT OPERATOR." << endl;
116
117 
 
118
119
 if (this != &other)
        if (this != &other)  {
{
120
121 delete m_p;
            delete m_p;
122
123 
 
124
125 m_p = other.m_p;
            m_p = other.m_p;
126
127 other.m_p = NULL;
            other.m_p = NULL;
128
129 }
        }
130
131 
 
132
133 return *this;
        return *this;
134
135 }
    }
136
137 #endif // #ifdef MOVABLE
#endif // #ifdef MOVABLE
138
139 
 
140
141
 ~remote_integer()
    ~remote_integer()  {
{
142
143 cout << "Destructor." << endl;
        cout << "Destructor." << endl;
144
145 
 
146
147 delete m_p;
        delete m_p;
148
149 }
    }
150
151 
 
152
153
 int get() const
    int get() const  {
{
154
155 return m_p ? *m_p : 0;
        return m_p ? *m_p : 0;
156
157 }
    }
158
159 
 
160
161 private:
private:
162
163 int * m_p;
    int * m_p;
164
165 };
};
166
167 
 
168
169
 remote_integer square(const remote_integer& r)
remote_integer square(const remote_integer& r)  {
{
170
171 const int i = r.get();
    const int i = r.get();
172
173 
 
174
175 return remote_integer(i * i);
    return remote_integer(i * i);
176
177 }
}
178
179 
 
180
181
 int main()
int main()  {
{
182
183 remote_integer a(8);
    remote_integer a(8);
184
185 
 
186
187 cout << a.get() << endl;
    cout << a.get() << endl;
188
189 
 
190
191 remote_integer b(10);
    remote_integer b(10);
192
193 
 
194
195 cout << b.get() << endl;
    cout << b.get() << endl;
196
197 
 
198
199 b = square(a);
    b = square(a);
200
201 
 
202
203 cout << b.get() << endl;
    cout << b.get() << endl;
204
205 }
}
206
207 
 
208
209 //C:\Temp>cl /EHsc /nologo /W4 remote.cpp
//C:\Temp>cl /EHsc /nologo /W4 remote.cpp
210
211 //remote.cpp
//remote.cpp
212
213 
 
214
215 //C:\Temp>remote
//C:\Temp>remote
216
217 Unary constructor.
Unary constructor.
218
219 8
8
220
221 Unary constructor.
Unary constructor.
222
223 10
10
224
225 Unary constructor.
Unary constructor.
226
227 Copy assignment operator.
Copy assignment operator.
228
229 Destructor.
Destructor.
230
231 64
64
232
233 Destructor.
Destructor.
234
235 Destructor.
Destructor.
236
237 
 
238
239 //C:\Temp>cl /EHsc /nologo /W4 /DMOVABLE //remote.cpp
//C:\Temp>cl /EHsc /nologo /W4 /DMOVABLE //remote.cpp
240
241 //remote.cpp
//remote.cpp
242
243 
 
244
245 //C:\Temp>remote
//C:\Temp>remote
246
247 Unary constructor.
Unary constructor.
248
249 8
8
250
251 Unary constructor.
Unary constructor.
252
253 10
10
254
255 Unary constructor.
Unary constructor.
256
257 MOVE ASSIGNMENT OPERATOR.
MOVE ASSIGNMENT OPERATOR.
258
259 Destructor.
Destructor.
260
261 64
64
262
263 Destructor.
Destructor.
264
265 Destructor.
Destructor.
266
267
 
 
There are several things to notice here.
这里有几点需要注意:
 
·         The copy and move constructors are overloaded, and the copy and move assignment operators are overloaded.  We've already seen what happens to functions overloaded on const Type& and Type&& .  This is what allows b = square(a); to automatically select the move assignment operator when it's available.
拷贝构造函数和move构造函数式重载版本,赋值操作和move赋值操作也是重载版本,我们已经看到当函数通过const Type&和Type&&进行重载时,结果的不同。当move语义可用时,b=square(a)将会选择move赋值操作。
·         Instead of dynamically allocating memory, the move constructor and move assignment operator simply steal it from other .  When stealing, we copy other's pointer and then null it out.  When other is destroyed, its destructor will do nothing.
move构造函数和move赋值操作只是简单的将内存从other那里“偷”了过来,而不是重新分配新的内存。当我们“偷”内存时,我们只是复制other的指向内存的指针,然后other的指针置为null。当other被摧毁时,析构函数什么都不用干(不用delete)。
·         Both the copy and move assignment operators need self-assignment checks.  It's well-known why copy assignment operators need self-assignment checks.  This is because plain old data types like ints can be assigned to themselves harmlessly (e.g. with x = x;), so user-defined data types should also be harmlessly self-assignable.  Self-assignment virtually never happens in handwritten code, but it can easily happen inside algorithms like std::sort() .  In C++0x, algorithms like std::sort() can move elements around instead of copying them.  The same potential for self-assignment exists here.
普通赋值操作和move赋值操作都需要进行自我赋值检查,赋值操作需要进行自我赋值检查是广为人知的。这是因为像int这种内建类型可以正确的自我赋值(例如:x=x),所以,用户的自定义类型也应该可以正确的进行自我赋值,自我赋值实际上在手写代码里面是不存在的,但是在类似std::sort()之类的算法中,却很常见。在C++0x中,像std::sort()之类的算法使用了move语义而非拷贝语义,所以同样的move赋值操作也需要进行自我赋值检查。
At this point, you may be wondering how this interacts with automatically generated ("implicitly declared" in Standardese) constructors and assignment operators.
这样,你可能会想move拷贝构造函数和move赋值操作和编译器自动生成拷贝构造函数和赋值操作之间是什么关系呢,会不会自动生成move的呢。
·         Move constructors and move assignment operators are never implicitly declared.
Move构造函数和move赋值操作都不会自动生成。
·         The implicit declaration of a default constructor is inhibited by any user-declared constructors, including copy constructors and move constructors.
如果用户声明了构造函数,包括拷贝构造函数和move构造函数,默认构造函数将不会自动生成。
·         The implicit declaration of a copy constructor is inhibited by a user-declared copy constructor, but not a user-declared move constructor.
用户定义了拷贝构造函数以后,编译器将不会再自动生成拷贝构造函数,但是move构造函数例外。
·         The implicit declaration of a copy assignment operator is inhibited by a user-declared copy assignment operator, but not a user-declared move assignment operator.
用户定义了赋值操作以后,编译器将不会再自动生成赋值操作,但是move赋值操作例外。
Basically, the automatic generation rules don't interact with move semantics, except that declaring a move constructor, like declaring any constructor, inhibits the implicitly declared default constructor.
基本上,除了move构造函数会阻止自动生成默认构造函数以外,自动生成规则不影响move语义。
 
move semantics: moving from lvalues
move 语义:从左值move 
Now, what if you like to write your copy constructors in terms of your copy assignment operators?  You might attempt to write your move constructors in terms of your move assignment operators.  This is possible, but you have to be careful.  Here's the wrong way to do it:
现在,如果你在拷贝构造函数中使用赋值操作会怎么样呢?你可能会在move构造函数中使用你的move赋值操作。这是可能的,但是你必须小心。下面是一种错误的使用方法:
 
  1 //C:\Temp>type unified_wrong.cpp
//C:\Temp>type unified_wrong.cpp
  2
  3 #include <stddef.h>
#include <stddef.h>
  4
  5 #include <iostream>
#include <iostream>
  6
  7 #include <ostream>
#include <ostream>
  8
  9 using namespace std;
using namespace std;
 10
 11 
 
 12
 13
 class remote_integer
class remote_integer  {
{
 14
 15 public:
public:
 16
 17
 remote_integer()
    remote_integer()  {
{
 18
 19 cout << "Default constructor." << endl;
        cout << "Default constructor." << endl;
 20
 21 
 
 22
 23 m_p = NULL;
        m_p = NULL;
 24
 25 }
    }
 26
 27 
 
 28
 29
 explicit remote_integer(const int n)
    explicit remote_integer(const int n)  {
{
 30
 31 cout << "Unary constructor." << endl;
        cout << "Unary constructor." << endl;
 32
 33 
 
 34
 35 m_p = new int(n);
        m_p = new int(n);
 36
 37 }
    }
 38
 39 
 
 40
 41
 remote_integer(const remote_integer& other)
    remote_integer(const remote_integer& other)  {
{
 42
 43 cout << "Copy constructor." << endl;
        cout << "Copy constructor." << endl;
 44
 45 
 
 46
 47 m_p = NULL;
        m_p = NULL;
 48
 49 *this = other;
        *this = other;
 50
 51 }
    }
 52
 53 
 
 54
 55 #ifdef MOVABLE
#ifdef MOVABLE
 56
 57
 remote_integer(remote_integer&& other)
    remote_integer(remote_integer&& other)  {
{
 58
 59 cout << "MOVE CONSTRUCTOR." << endl;
        cout << "MOVE CONSTRUCTOR." << endl;
 60
 61 
 
 62
 63 m_p = NULL;
        m_p = NULL;
 64
 65 *this = other; // WRONG
        *this = other; // WRONG
 66
 67 }
    }
 68
 69 #endif // #ifdef MOVABLE
#endif // #ifdef MOVABLE
 70
 71 
 
 72
 73
 remote_integer& operator=(const remote_integer& other)
    remote_integer& operator=(const remote_integer& other)  {
{
 74
 75 cout << "Copy assignment operator." << endl;
        cout << "Copy assignment operator." << endl;
 76
 77 
 
 78
 79
 if (this != &other)
        if (this != &other)  {
{
 80
 81 delete m_p;
            delete m_p;
 82
 83 
 
 84
 85
 if (other.m_p)
            if (other.m_p)  {
{
 86
 87 m_p = new int(*other.m_p);
                m_p = new int(*other.m_p);
 88
 89
 } else
            } else  {
{
 90
 91 m_p = NULL;
                m_p = NULL;
 92
 93 }
            }
 94
 95 }
        }
 96
 97 
 
 98
 99 return *this;
        return *this;
100
101 }
    }
102
103 
 
104
105 #ifdef MOVABLE
#ifdef MOVABLE
106
107
 remote_integer& operator=(remote_integer&& other)
    remote_integer& operator=(remote_integer&& other)  {
{
108
109 cout << "MOVE ASSIGNMENT OPERATOR." << endl;
        cout << "MOVE ASSIGNMENT OPERATOR." << endl;
110
111 
 
112
113
 if (this != &other)
        if (this != &other)  {
{
114
115 delete m_p;
            delete m_p;
116
117 
 
118
119 m_p = other.m_p;
            m_p = other.m_p;
120
121 other.m_p = NULL;
            other.m_p = NULL;
122
123 }
        }
124
125 
 
126
127 return *this;
        return *this;
128
129 }
    }
130
131 #endif // #ifdef MOVABLE
#endif // #ifdef MOVABLE
132
133 
 
134
135
 ~remote_integer()
    ~remote_integer()  {
{
136
137 cout << "Destructor." << endl;
        cout << "Destructor." << endl;
138
139 
 
140
141 delete m_p;
        delete m_p;
142
143 }
    }
144
145 
 
146
147
 int get() const
    int get() const  {
{
148
149 return m_p ? *m_p : 0;
        return m_p ? *m_p : 0;
150
151 }
    }
152
153 
 
154
155 private:
private:
156
157 int * m_p;
    int * m_p;
158
159 };
};
160
161 
 
162
163
 remote_integer frumple(const int n)
remote_integer frumple(const int n)  {
{
164
165
 if (n == 1729)
    if (n == 1729)  {
{
166
167 return remote_integer(1729);
        return remote_integer(1729);
168
169 }
    }
170
171 
 
172
173 remote_integer ret(n * n);
    remote_integer ret(n * n);
174
175 
 
176
177 return ret;
    return ret;
178
179 }
}
180
181 
 
182
183
 int main()
int main()  {
{
184
185 remote_integer x = frumple(5);
    remote_integer x = frumple(5);
186
187 
 
188
189 cout << x.get() << endl;
    cout << x.get() << endl;
190
191 
 
192
193 remote_integer y = frumple(1729);
    remote_integer y = frumple(1729);
194
195 
 
196
197 cout << y.get() << endl;
    cout << y.get() << endl;
198
199 }
}
200
201 
 
202
203 //C:\Temp>cl /EHsc /nologo /W4 /O2 unified_wrong.cpp
//C:\Temp>cl /EHsc /nologo /W4 /O2 unified_wrong.cpp
204
205 //unified_wrong.cpp
//unified_wrong.cpp
206
207 
 
208
209 //C:\Temp>unified_wrong
//C:\Temp>unified_wrong
210
211 Unary constructor.
Unary constructor.
212
213 Copy constructor.
Copy constructor.
214
215 Copy assignment operator.
Copy assignment operator.
216
217 Destructor.
Destructor.
218
219 25
25
220
221 Unary constructor.
Unary constructor.
222
223 1729
1729
224
225 Destructor.
Destructor.
226
227 Destructor.
Destructor.
228
229 
 
230
231 //C:\Temp>cl /EHsc /nologo /W4 /O2 /DMOVABLE unified_wrong.cpp
//C:\Temp>cl /EHsc /nologo /W4 /O2 /DMOVABLE unified_wrong.cpp
232
233 //unified_wrong.cpp
//unified_wrong.cpp
234
235 
 
236
237 //C:\Temp>unified_wrong
//C:\Temp>unified_wrong
238
239 Unary constructor.
Unary constructor.
240
241 MOVE CONSTRUCTOR.
MOVE CONSTRUCTOR.
242
243 Copy assignment operator.
Copy assignment operator.
244
245 Destructor.
Destructor.
246
247 25
25
248
249 Unary constructor.
Unary constructor.
250
251 1729
1729
252
253 Destructor.
Destructor.
254
255 Destructor.
Destructor.
256
257
 
 
(The compiler is performing the RVO here, but not the NRVO.  As I mentioned earlier, some copy constructor calls are elided by the RVO and NRVO, but the compiler isn't always able to apply them.  Move constructors optimize the remaining cases.)
 (编译器进行了返回值优化RVO,但不是具名返回值优化NRVO。之前提到,有些拷贝构造函数被RVO或NRVO优化掉了,但是并不是所有的情况下都能优化掉,move构造函数可以优化剩下的情况。)
The line marked WRONG inside the move constructor is calling the copy assignment operator!  This compiles and runs, but it defeats the purpose of the move constructor.
在有WRONG的那一行,在move构造函数中调用了赋值操作,编译通过了,但结果却并不对(因为那个赋值操作调用的是普通的赋值操作)。
What happened?  Remember from C++98/03 that named lvalue references are lvalues (if you say int& r = *p; then r is an lvalue) and unnamed lvalue references are also lvalues (given vector<int> v(10, 1729), calling v[0] returns int& , an unnamed lvalue reference whose address you can take).  Rvalue references behave differently:
为什么呢?在C++98/03中,具名的左值引用是左值,不具名的左值引用还是左值。但是右值引用却不同:
·         Named rvalue references are lvalues.
具名的右值引用是左值。
·         Unnamed rvalue references are rvalues.
不具名的右值引用才是右值。
A named rvalue reference is an lvalue because it can be repeatedly mentioned, with multiple operations performed on it.  If instead it were an rvalue, then the first operation performed could steal from it, affecting subsequent operations.  Stealing is supposed to be unobservable, so this is forbidden.  On the other hand, unnamed rvalue references can't be repeatedly mentioned, so they can preserve their rvalueness.
具名的右值引用是左值的原因在于它可以被重复的使用,对它进行各种各样的操作。如果它还是右值的话,在第一个操作中被“偷”走了,后面的操作将会受到影响。“偷”应该不被察觉到(应该和没有“偷”时表现一样),所以不能这样做。另一方面,不具名的右值引用不能被重复的使用,所以它们仍然是右值。
If you're really intent on implementing your move constructors in terms of your move assignment operators, you'll need the ability to move from lvalues by treating them as rvalues.  This is powered by std::move() from C++0x <utility>, which will be in VC10 (in fact, it's already in my development build), but because it's not in the VC10 CTP, I'll show you how to write it from scratch:
如果你确实想在move构造函数中使用move赋值操作,你需要把左值当做右值对待。这可以通过使用C++0x <utility>中的std::move()来解决。VC10TCP版本中没有,但是VC10中会有,所以我会教你从头做起:
 
  1 //C:\Temp>type unified_right.cpp
//C:\Temp>type unified_right.cpp
  2
  3 #include <stddef.h>
#include <stddef.h>
  4
  5 #include <iostream>
#include <iostream>
  6
  7 #include <ostream>
#include <ostream>
  8
  9 using namespace std;
using namespace std;
 10
 11 
 
 12
 13
 template <typename T> struct RemoveReference
template <typename T> struct RemoveReference  {
{
 14
 15 typedef T type;
     typedef T type;
 16
 17 };
};
 18
 19 
 
 20
 21
 template <typename T> struct RemoveReference<T&>
template <typename T> struct RemoveReference<T&>  {
{
 22
 23 typedef T type;
     typedef T type;
 24
 25 };
};
 26
 27 
 
 28
 29
 template <typename T> struct RemoveReference<T&&>
template <typename T> struct RemoveReference<T&&>  {
{
 30
 31 typedef T type;
     typedef T type;
 32
 33 };
};
 34
 35 
 
 36
 37
 template <typename T> typename RemoveReference<T>::type&& Move(T&& t)
template <typename T> typename RemoveReference<T>::type&& Move(T&& t)  {
{
 38
 39 return t;
    return t;
 40
 41 }
}
 42
 43 
 
 44
 45
 class remote_integer
class remote_integer  {
{
 46
 47 public:
public:
 48
 49
 remote_integer()
    remote_integer()  {
{
 50
 51 cout << "Default constructor." << endl;
        cout << "Default constructor." << endl;
 52
 53 
 
 54
 55 m_p = NULL;
        m_p = NULL;
 56
 57 }
    }
 58
 59 
 
 60
 61
 explicit remote_integer(const int n)
    explicit remote_integer(const int n)  {
{
 62
 63 cout << "Unary constructor." << endl;
        cout << "Unary constructor." << endl;
 64
 65 
 
 66
 67 m_p = new int(n);
        m_p = new int(n);
 68
 69 }
    }
 70
 71 
 
 72
 73
 remote_integer(const remote_integer& other)
    remote_integer(const remote_integer& other)  {
{
 74
 75 cout << "Copy constructor." << endl;
        cout << "Copy constructor." << endl;
 76
 77 
 
 78
 79 m_p = NULL;
        m_p = NULL;
 80
 81 *this = other;
        *this = other;
 82
 83 }
    }
 84
 85 
 
 86
 87 #ifdef MOVABLE
#ifdef MOVABLE
 88
 89
 remote_integer(remote_integer&& other)
    remote_integer(remote_integer&& other)  {
{
 90
 91 cout << "MOVE CONSTRUCTOR." << endl;
        cout << "MOVE CONSTRUCTOR." << endl;
 92
 93 
 
 94
 95 m_p = NULL;
        m_p = NULL;
 96
 97 *this = Move(other); // RIGHT
        *this = Move(other); // RIGHT
 98
 99 }
    }
100
101 #endif // #ifdef MOVABLE
#endif // #ifdef MOVABLE
102
103 
 
104
105
 remote_integer& operator=(const remote_integer& other)
    remote_integer& operator=(const remote_integer& other)  {
{
106
107 cout << "Copy assignment operator." << endl;
        cout << "Copy assignment operator." << endl;
108
109 
 
110
111
 if (this != &other)
        if (this != &other)  {
{
112
113 delete m_p;
            delete m_p;
114
115 
 
116
117
 if (other.m_p)
            if (other.m_p)  {
{
118
119 m_p = new int(*other.m_p);
                m_p = new int(*other.m_p);
120
121
 } else
            } else  {
{
122
123 m_p = NULL;
                m_p = NULL;
124
125 }
            }
126
127 }
        }
128
129 
 
130
131 return *this;
        return *this;
132
133 }
    }
134
135 
 
136
137 #ifdef MOVABLE
#ifdef MOVABLE
138
139
 remote_integer& operator=(remote_integer&& other)
    remote_integer& operator=(remote_integer&& other)  {
{
140
141 cout << "MOVE ASSIGNMENT OPERATOR." << endl;
        cout << "MOVE ASSIGNMENT OPERATOR." << endl;
142
143 
 
144
145
 if (this != &other)
        if (this != &other)  {
{
146
147 delete m_p;
            delete m_p;
148
149 
 
150
151 m_p = other.m_p;
            m_p = other.m_p;
152
153 other.m_p = NULL;
            other.m_p = NULL;
154
155 }
        }
156
157 
 
158
159 return *this;
        return *this;
160
161 }
    }
162
163 #endif // #ifdef MOVABLE
#endif // #ifdef MOVABLE
164
165 
 
166
167
 ~remote_integer()
    ~remote_integer()  {
{
168
169 cout << "Destructor." << endl;
        cout << "Destructor." << endl;
170
171 
 
172
173 delete m_p;
        delete m_p;
174
175 }
    }
176
177 
 
178
179
 int get() const
    int get() const  {
{
180
181 return m_p ? *m_p : 0;
        return m_p ? *m_p : 0;
182
183 }
    }
184
185 
 
186
187 private:
private:
188
189 int * m_p;
    int * m_p;
190
191 };
};
192
193 
 
194
195
 remote_integer frumple(const int n)
remote_integer frumple(const int n)  {
{
196
197
 if (n == 1729)
    if (n == 1729)  {
{
198
199 return remote_integer(1729);
        return remote_integer(1729);
200
201 }
    }
202
203 
 
204
205 remote_integer ret(n * n);
    remote_integer ret(n * n);
206
207 
 
208
209 return ret;
    return ret;
210
211 }
}
212
213 
 
214
215
 int main()
int main()  {
{
216
217 remote_integer x = frumple(5);
    remote_integer x = frumple(5);
218
219 
 
220
221 cout << x.get() << endl;
    cout << x.get() << endl;
222
223 
 
224
225 remote_integer y = frumple(1729);
    remote_integer y = frumple(1729);
226
227 
 
228
229 cout << y.get() << endl;
    cout << y.get() << endl;
230
231 }
}
232
233 
 
234
235 //C:\Temp>cl /EHsc /nologo /W4 /O2 /DMOVABLE unified_right.cpp
//C:\Temp>cl /EHsc /nologo /W4 /O2 /DMOVABLE unified_right.cpp
236
237 //unified_right.cpp
//unified_right.cpp
238
239 
 
240
241 //C:\Temp>unified_right
//C:\Temp>unified_right
242
243 Unary constructor.
Unary constructor.
244
245 MOVE CONSTRUCTOR.
MOVE CONSTRUCTOR.
246
247 MOVE ASSIGNMENT OPERATOR.
MOVE ASSIGNMENT OPERATOR.
248
249 Destructor.
Destructor.
250
251 25
25
252
253 Unary constructor.
Unary constructor.
254
255 1729
1729
256
257 Destructor.
Destructor.
258
259 Destructor.
Destructor.
260
261
 
 
(I'll refer to std::move() and my Move() interchangeably, since they're implemented identically.)  How does std::move() work?  For the moment, I'm going to say that "magic is involved".  (There's a full explanation below; it's not complicated, but it involves template argument deduction and reference collapsing, which we'll encounter while looking at perfect forwarding.)  I can skip over the magic with concrete examples.  Given an lvalue of type string, like up from the overload resolution examples above, std::move(up) calls string&& std::move(string&) .  This returns an unnamed rvalue reference, which is an rvalue.  Given an rvalue of type string, like strange() from above, std::move(strange()) calls string&& std::move(string&&) .  Again, this returns an unnamed rvalue reference, which is an rvalue.
(我将交替的使用std::move和Move,因为它们的实现时一样的)它是怎样工作的呢?现在,我要说“这是个魔法”(后面将会有完整的解释,并不是很复杂,但是它与模板参数演绎和引用合并有关,在讲完美转发的时候我们还会遇到)。我可以用一个具体的例子来略过这个“魔法”:给定一个string类型的左值,像前面例子中的up,std::move(up)调用 string&& std::move(string&), 这个函数返回一个不具名的右值引用,也就是右值。给定一个string类型的右值,像前面例子中的strange(), std::(strange()) 调用 string&& std::move(string&&),这个函数还是返回一个不具名的右值,还是右值。
std::move() is useful in other places than implementing move constructors in terms of move assignment operators.  Whenever you reach a point where you can say "I have an lvalue here, and its value is going to cease to matter" (e.g. because it's going to be destroyed or assigned to), you can write std::move(your lvalue expression) in order to activate move semantics.
std::move除了能实现move构造函数中是呀move赋值操作以外,还可以在其他地方使用。无论在任何时候,你说“我有一个左值,但是它的值已经不再重要了”,这时你可以使用std::move(你的左值)来使用move语义。
 
move semantics: movable members
move语义:movable成员
C++0x's Standard classes (e.g. vector, string, regex) have move constructors and move assignment operators, and we've seen how to implement them in our own classes that manually manage resources (e.g. remote_integer).  But what about classes containing movable data members (e.g. vector, string, regex, remote_integer)?  The compiler won't automatically generate move constructors and move assignment operators for us.  So, we'll need to write them ourselves.  Fortunately, with std::move() , this is extremely easy:
C++0x标准类(像 vector, string, regex) 都实现了move构造函数和move赋值操作,而且我们已经学习了怎样在我们自己的类中实现它们来手动管理资源(像 remote_integer). 但是当类中含有movable成员变量是,会怎样呢 (像 vector, string, regex, remote_integer)?  编译器不会自动生成move构造函数和move赋值操作。所以,我们要自己实现,幸运的是我们有了std::move后,实现起来非常简单:
 
  1 //C:\Temp>type point.cpp
//C:\Temp>type point.cpp
  2
  3 #include <stddef.h>
#include <stddef.h>
  4
  5 #include <iostream>
#include <iostream>
  6
  7 #include <ostream>
#include <ostream>
  8
  9 using namespace std;
using namespace std;
 10
 11 
 
 12
 13
 template <typename T> struct RemoveReference
template <typename T> struct RemoveReference  {
{
 14
 15 typedef T type;
     typedef T type;
 16
 17 };
};
 18
 19 
 
 20
 21
 template <typename T> struct RemoveReference<T&>
template <typename T> struct RemoveReference<T&>  {
{
 22
 23 typedef T type;
     typedef T type;
 24
 25 };
};
 26
 27 
 
 28
 29
 template <typename T> struct RemoveReference<T&&>
template <typename T> struct RemoveReference<T&&>  {
{
 30
 31 typedef T type;
     typedef T type;
 32
 33 };
};
 34
 35 
 
 36
 37
 template <typename T> typename RemoveReference<T>::type&& Move(T&& t)
template <typename T> typename RemoveReference<T>::type&& Move(T&& t)  {
{
 38
 39 return t;
    return t;
 40
 41 }
}
 42
 43 
 
 44
 45
 class remote_integer
class remote_integer  {
{
 46
 47 public:
public:
 48
 49
 remote_integer()
    remote_integer()  {
{
 50
 51 cout << "Default constructor." << endl;
        cout << "Default constructor." << endl;
 52
 53 
 
 54
 55 m_p = NULL;
        m_p = NULL;
 56
 57 }
    }
 58
 59 
 
 60
 61
 explicit remote_integer(const int n)
    explicit remote_integer(const int n)  {
{
 62
 63 cout << "Unary constructor." << endl;
        cout << "Unary constructor." << endl;
 64
 65 
 
 66
 67 m_p = new int(n);
        m_p = new int(n);
 68
 69 }
    }
 70
 71 
 
 72
 73
 remote_integer(const remote_integer& other)
    remote_integer(const remote_integer& other)  {
{
 74
 75 cout << "Copy constructor." << endl;
        cout << "Copy constructor." << endl;
 76
 77 
 
 78
 79
 if (other.m_p)
        if (other.m_p)  {
{
 80
 81 m_p = new int(*other.m_p);
            m_p = new int(*other.m_p);
 82
 83
 } else
        } else  {
{
 84
 85 m_p = NULL;
            m_p = NULL;
 86
 87 }
        }
 88
 89 }
    }
 90
 91 
 
 92
 93
 remote_integer(remote_integer&& other)
    remote_integer(remote_integer&& other)  {
{
 94
 95 cout << "MOVE CONSTRUCTOR." << endl;
        cout << "MOVE CONSTRUCTOR." << endl;
 96
 97 
 
 98
 99 m_p = other.m_p;
        m_p = other.m_p;
100
101 other.m_p = NULL;
        other.m_p = NULL;
102
103 }
    }
104
105 
 
106
107
 remote_integer& operator=(const remote_integer& other)
    remote_integer& operator=(const remote_integer& other)  {
{
108
109 cout << "Copy assignment operator." << endl;
        cout << "Copy assignment operator." << endl;
110
111 
 
112
113
 if (this != &other)
        if (this != &other)  {
{
114
115 delete m_p;
            delete m_p;
116
117 
 
118
119
 if (other.m_p)
            if (other.m_p)  {
{
120
121 m_p = new int(*other.m_p);
                m_p = new int(*other.m_p);
122
123
 } else
            } else  {
{
124
125 m_p = NULL;
                m_p = NULL;
126
127 }
            }
128
129 }
        }
130
131 
 
132
133 return *this;
        return *this;
134
135 }
    }
136
137 
 
138
139
 remote_integer& operator=(remote_integer&& other)
    remote_integer& operator=(remote_integer&& other)  {
{
140
141 cout << "MOVE ASSIGNMENT OPERATOR." << endl;
        cout << "MOVE ASSIGNMENT OPERATOR." << endl;
142
143 
 
144
145
 if (this != &other)
        if (this != &other)  {
{
146
147 delete m_p;
            delete m_p;
148
149 
 
150
151 m_p = other.m_p;
            m_p = other.m_p;
152
153 other.m_p = NULL;
            other.m_p = NULL;
154
155 }
        }
156
157 
 
158
159 return *this;
        return *this;
160
161 }
    }
162
163 
 
164
165
 ~remote_integer()
    ~remote_integer()  {
{
166
167 cout << "Destructor." << endl;
        cout << "Destructor." << endl;
168
169 
 
170
171 delete m_p;
        delete m_p;
172
173 }
    }
174
175 
 
176
177
 int get() const
    int get() const  {
{
178
179 return m_p ? *m_p : 0;
        return m_p ? *m_p : 0;
180
181 }
    }
182
183 
 
184
185 private:
private:
186
187 int * m_p;
    int * m_p;
188
189 };
};
190
191 
 
192
193
 class remote_point
class remote_point  {
{
194
195 public:
public:
196
197 remote_point(const int x_arg, const int y_arg)
    remote_point(const int x_arg, const int y_arg)
198
199
 : m_x(x_arg), m_y(y_arg)
        : m_x(x_arg), m_y(y_arg)  { }
{ }
200
201 
 
202
203 remote_point(remote_point&& other)
    remote_point(remote_point&& other)
204
205 : m_x(Move(other.m_x)),
        : m_x(Move(other.m_x)),
206
207
 m_y(Move(other.m_y))
          m_y(Move(other.m_y))  { }
{ }
208
209 
 
210
211
 remote_point& operator=(remote_point&& other)
    remote_point& operator=(remote_point&& other)  {
{
212
213 m_x = Move(other.m_x);
        m_x = Move(other.m_x);
214
215 m_y = Move(other.m_y);
        m_y = Move(other.m_y);
216
217 return *this;
        return *this;
218
219 }
    }
220
221 
 
222
223
 int x() const
    int x() const  { return m_x.get(); }
{ return m_x.get(); }
224
225
 int y() const
    int y() const  { return m_y.get(); }
{ return m_y.get(); }
226
227 
 
228
229 private:
private:
230
231 remote_integer m_x;
    remote_integer m_x;
232
233 remote_integer m_y;
    remote_integer m_y;
234
235 };
};
236
237 
 
238
239
 remote_point five_by_five()
remote_point five_by_five()  {
{
240
241 return remote_point(5, 5);
    return remote_point(5, 5);
242
243 }
}
244
245 
 
246
247
 remote_point taxicab(const int n)
remote_point taxicab(const int n)  {
{
248
249
 if (n == 0)
    if (n == 0)  {
{
250
251 return remote_point(1, 1728);
        return remote_point(1, 1728);
252
253 }
    }
254
255 
 
256
257 remote_point ret(729, 1000);
    remote_point ret(729, 1000);
258
259 
 
260
261 return ret;
    return ret;
262
263 }
}
264
265 
 
266
267
 int main()
int main()  {
{
268
269 remote_point p = taxicab(43112609);
    remote_point p = taxicab(43112609);
270
271 
 
272
273 cout << "(" << p.x() << ", " << p.y() << ")" << endl;
    cout << "(" << p.x() << ", " << p.y() << ")" << endl;
274
275 
 
276
277 p = five_by_five();
    p = five_by_five();
278
279 
 
280
281 cout << "(" << p.x() << ", " << p.y() << ")" << endl;
    cout << "(" << p.x() << ", " << p.y() << ")" << endl;
282
283 }
}
284
285 
 
286
287 //C:\Temp>cl /EHsc /nologo /W4 /O2 point.cpp
//C:\Temp>cl /EHsc /nologo /W4 /O2 point.cpp
288
289 //point.cpp
//point.cpp
290
291 
 
292
293 //C:\Temp>point
//C:\Temp>point
294
295 Unary constructor.
Unary constructor.
296
297 Unary constructor.
Unary constructor.
298
299 MOVE CONSTRUCTOR.
MOVE CONSTRUCTOR.
300
301 MOVE CONSTRUCTOR.
MOVE CONSTRUCTOR.
302
303 Destructor.
Destructor.
304
305 Destructor.
Destructor.
306
307 (729, 1000)
(729, 1000)
308
309 Unary constructor.
Unary constructor.
310
311 Unary constructor.
Unary constructor.
312
313 MOVE ASSIGNMENT OPERATOR.
MOVE ASSIGNMENT OPERATOR.
314
315 MOVE ASSIGNMENT OPERATOR.
MOVE ASSIGNMENT OPERATOR.
316
317 Destructor.
Destructor.
318
319 Destructor.
Destructor.
320
321 (5, 5)
(5, 5)
322
323 Destructor.
Destructor.
324
325 Destructor.
Destructor.
326
327
 
 
As you can see, memberwise moves are trivial to write.  Note that remote_point's move assignment operator doesn't need to check for self-assignment because remote_integer already does.  Also note that remote_point's implicitly declared copy constructor, copy assignment operator, and destructor do the right things.
和你看到的一样,move成员是很无聊的。注意remote_point的move赋值操作没有进行自我赋值检查,因为remote_integer已经检查过了。同样也注意到remote_point自动生成的拷贝构造函数,赋值操作和析构函数都工作正常。
A final reminder: whenever possible, you should implement move constructors and move assignment operators for your copyable classes, because the compiler won't do it for you.  Not only will ordinary use of those classes automatically pick up move semantics, but STL containers and algorithms will also take advantage of move semantics, replacing expensive copies with cheap moves.
最后提示,无论在任何时候,你都应该为copyable的类实现move构造函数和move赋值函数,因为编译器不会自动生成。并不只是因为move语义会在通常情况下被使用,而是STL容器和算法会从move语义中得到好处:用简单的move代替昂贵的拷贝。
 
	posted on 2009-05-28 20:51 
尹东斐 阅读(1612) 
评论(0)  编辑 收藏 引用