| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> 理解std::move和std::forward -> 正文阅读 |
|
[C++知识库]理解std::move和std::forward |
函数返回值的"&&"部分表明std::move返回的是一个右值引用。但是呢,正如Item 28条解释的那样,如果T的类型恰好是一个左值引用,T&&的类型就会也会是左值引用。为了阻止这种事情的发生,我们用到了type trait(请看Item 9),在T上面应用std::remove_reference,它的效果就是“去除”T身上的引用,因此保证了"&&"应用到了一个非引用的类型上面。这就确保了std::move真正的返回的是一个右值引用(rvalue reference),这很重要,因为函数返回的rvalue reference就是右值(rvalue).因此,std::move就做了一件事情:将它的参数转换成了右值(rvalue)。 说一句题外话,std::move可以更优雅的在C++14中实现。感谢返回函数类型推导(function return type deduction 请看Item 3),感谢标准库模板别名(alias template) std::remove_reference_t (请看Item 9), std::move 可以这样写:
看起来舒服多了,因为std::move除了将它的参数转换成右值外什么都不做,所以有人说应该给它换个名字,比如说叫 rvalue_cast 可能会好些。话虽如此,它现在的名字仍然就是 std::move .所以记住 std::move 做什么不做什么很重要。它只作转换,不做move。
但是Annotation的构造函数只需要读取text的值。并不需要修改它。根据一个历史悠久的传统:能使用const的时候尽量使用。你修改了构造函数的声明,text改为const:
为了避免拷贝text到对象成员变量带来拷贝代价。你继续忠实于Item 41的建议,对text应用std::move,因此产生出一个rvalue:
这样的代码通过了编译,链接,最后运行。而且把成员变量value设置成text的值。代码跟你想象中的完美情况唯一不同的一点是,它没有对text执行move到value,而是拷贝了text的值到value.text确实被std::move转化成了rvalue,但是text被声明为const std::string.所以在cast之前,text是一个const std::string类型的lvalue.cast的结果是一个const std::string的rvalue,但是自始至终,const的性质一直没变。
在Annotation的构造函数的成员初始化列表(member initialization list), std::move(text) 的结果是const std::string的rvalue.这个rvalue不能传递给std::string的move构造函数,因为move构造函数接收的是非const的std::string的rvalue引用。然而,因为lvalue-reference-to-const的参数类型可以被const rvalue匹配上,所以rvalue可以被传递给拷贝构造函数.因此即使text被转换成了rvalue,上文中的成员初始化仍调用了std::string的拷贝构造函数!这样的行为对于保持const的正确性是必须的。从一个对象里move出一个值通常会改变这个对象,所以语言不允许将const对象传递给像move constructor这样的会改变次对象的函数。
首先,如果你想对这些对象执行move操作,就不要把它们声明为const,对const对象的move请求通常会悄悄的执行到copy操作上。 std::forward是一个有条件的转化。为了理解它何时转化何时不转化,我们来回想一下std::forward的典型的使用场景。最常见的场景是:一个函数模板(function template)接受一个universal reference参数,将它传递给另外一个函数(作参数):
请看下面对logAndProcess的两个调用,一个使用的lvalue,另一个使用的rvalue:
在logAndProcess的实现中,参数param被传递给了函数process.process按照参数类型是lvalue或者rvalue都做了重载。当我们用lvalue调用logAndProcess时,我们自然地期望:
如果要使用std::forward来实现同样的行为,代码像下面这样写:
请注意到:首先,std::move只需要一个函数参数(rhs.s), std::forward不只需要一个函数参数(rhs.s),还需要一个模板类型参数(std::string).然后,注意到我们传递给std::forward的类型是非引用类型(non-reference),因为这就意味着传递的那个参数是一个rvalue(请看Item 28)。综上,这就意味着std::move比std::forward用起来更方便(至少少敲了不少字),免去了让我们传递一个表示函数参数是否是一个rvalue的类型参数。消除了传递错误类型(比如说,传一个std::string&,可以导致数据成员s被拷贝构造,而不是想要的move构造)的可能性。 4.std::forward转发问题通常针对的是模板函数。 引用:理解std::move和std::forward_土戈的博客-CSDN博客_std::forward C++11 模板 一:彻底理解 std::move 和 std::forward - 知乎 |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/23 16:59:47- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |