鸽纸

导航

c++11的 move并没有实际move

c++11的 move并没有实际move

  首先看第一个例子:

 1 #include <iostream > // std::cout
 2 #include <utility > // std::move
 3 #include <vector > // std::vector
 4 #include <string > // std::string
 5 
 6 int main() {
 7 
 8     std::string str = "Hello world.";
 9     std::vector <std::string > v;
10 
11     // 将 使 用 push_back(const T&), 即 产 生 拷 贝 行 为
12     v.push_back(str);
13     // 将 输 出 "str: Hello world."
14     std::cout << "str: " << str << std::endl;
15 
16     // 将 使 用 push_back(const T&&), 不 会 出 现 拷 贝 行 为
17     // 而 整 个 字 符 串 会 被 移 动 到 vector 中, 所 以 有 时 候 std::move 会 用 来 减 少 拷 贝 出现 的 开 销
18     // 这 步 操 作 后 , str 中 的 值 会 变 为 空
19     v.push_back(std::move(str));
20     // 将 输 出 "str: "
21     std::cout << "str: " << str << std::endl;
22 
23     return 0;
24 }

最后打印为"str: ",和我一开始理解的move语义一致,str被移入了vector中,所以str为空。

再看下一段代码,这是在讲完美转发时的一个例子:

 1 # include <iostream >
 2 # include <utility >
 3 void reference ( int & v) {
 4     std :: cout << " 左 值 引 用 " << std :: endl ;
 5 }
 6 void reference ( int && v) {
 7     std :: cout << " 右 值 引 用 " << std :: endl ;
 8 }
 9 template <typename T>
10 void pass (T&& v) {
11     std :: cout << " 普 通 传 参 :";
12     reference (v);
13     std :: cout << " std :: move 传 参 :";
14     reference (std :: move (v));
15     std :: cout << " std :: forward 传 参 :";
16     reference (std :: forward <T >(v));
17 }
18 
19 int main () {
20     std :: cout << " 传 递 右 值 :" << std :: endl ;
21     pass (1);
22 
23     std :: cout << " 传 递 左 值 :" << std :: endl ;
24     int v = 1;
25     pass (v);
26 
27     return 0;
28 }

输出结果为:

值 :
参 :
std :: move 参 :
std :: forward 参 :
值 :
参 :
std :: move 参 :
std :: forward 参 :

 令我困惑的是,在pass中,v明明先调用了reference (std :: move (v));然后又调用了一次reference (std :: forward <T >(v));

那么v不应该在第一次move后就已经被移走了吗?

答案是no。

我们看一下move的实现:

1 template <class _Ty>
2 _NODISCARD constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept { // forward _Arg as movable
3     return static_cast<remove_reference_t<_Ty>&&>(_Arg);
4 }

也就是说move仅仅只是做了个类型转换,将其转为右值引用类型,并未实际发生移动效果。

而前面第一个例子中的push_back中,实际触发了string的移动构造,导致str被真正移走。

所以,为验证这个想法,只需要简单修改第二个例子就可以验证:

 1 # include <iostream >
 2 # include <utility >
 3 int reference(int& v) {
 4     std::cout << " 左 值 引 用 " << std::endl;
 5     return v;
 6 }
 7 int reference(int&& v) {
 8     std::cout << " 右 值 引 用 " << std::endl;
 9     return std::move(v);
10 }
11 
12 template <typename T>
13 void pass(T&& v) {
14     std::cout << " 普 通 传 参 :";
15     reference(v);
16     std::cout << " std :: move 传 参 :";
17     int a= reference(std::move(v));
18     std::cout << " std :: forward 传 参 :";
19     int b = reference(std::forward <T >(v));
20 }
21 
22 int main() {
23     std::cout << " 传 递 右 值 :" << std::endl;
24     pass(1);
25 
26     std::cout << " 传 递 左 值 :" << std::endl;
27     int v = 1;
28     pass(v);
29 
30     return 0;
31 }

pass(1)时,v未被移走,而用下面int v = 1传递时,在执行完int a= reference(std::move(v));之后,v就已经不存在了,此处才发生了真正的移动操作。

posted on 2020-03-26 14:00  鸽纸  阅读(202)  评论(0编辑  收藏  举报