ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2020-03-26 14:01:28  阅读:188  来源: 互联网

标签:11 std cout int move c++ str include


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就已经不存在了,此处才发生了真正的移动操作。

标签:11,std,cout,int,move,c++,str,include
来源: https://www.cnblogs.com/gezi/p/12574054.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有