IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【Effective Modern C++】Chapter 5 右值引用、移动语义和完美转发 -> 正文阅读

[C++知识库]【Effective Modern C++】Chapter 5 右值引用、移动语义和完美转发

Chapter 5 右值引用、移动语义和完美转发

移动语义:用移动操作来替代昂贵的复制操作。

完美转发:函数模板转发其他函数,目标函数将接收到与转发函数所接受的完全相同的实参。

右值引用:让移动语义和完美转发成为可能。

实际情况:

  • std::move其实并没有移动任何东西…
  • 完美转发并不完美…
  • 移动操作的成本并不一定比复制低…
  • 移动语境中不一定能调到移动操作…
  • "type&&"并不总是表示右值引用…

C++规则:形参总是左值,即使其型别是右值引用。

23 理解std::move和std::forward

std::move

std::move是无条件的将实参强制转换成右值的函数模板。

C++14中std::move的实现类似:

template<typename T>
decltype(auto) move(T&& param)
{
	using ReturnType = remove_reference_t<T>&&;
	return static_cast<ReturnType>(param);
}

移动失败的场景:下面的代码看似使用了移动,实则是复制,原因在于text具有const属性,因此代码不应该允许常量对象传递到有可能改动他们的函数中(比如移动构造函数)。

class Base {
public:
	explicit Base(const std::string text) : value(std::move(text)){
	}
private:
	std::string value;
}

std::forward

std::forward是有条件的将实参强制转换成右值的函数模板。

典型场景如下,C++规则:形参总是左值 ,如果下面的代码中不加std::forward,则process拿到的参数一定是左值,而std::forward做的事情就是仅当用来初始化param的实参是个右值时,把param强制转换为右值型别。

void process(const string& lVal) {
    cout << "left" << endl;
}

void process(string&& rVal) {
    cout << "right" << endl;
}

template<typename T>
void function(T&& param) {
    // C++规则:形参总是左值 
    // 故当传入的param是右值时需要强制转换为右值才能实现完美转发
    process(std::forward<T>(param));
}

int main() {
    string s{"Hello."};
    function(s);  // 调用打印left的函数
    function(std::move(s));  // 调用打印right的函数

    return 0;
}

二者的区别:

  • std::move无条件的将实参强制转换成右值;
  • std::forward仅在特定条件(传入的实参被绑定到右值)下执行强制转换。

为什么std::forward不能代替std::move?

  1. 方便:std::move只需要实参,std::forward需要实参和模板类型。
  2. 减少错误的可能:对于实参是左值引用时,用std::move转换完可顺利调用移动构造函数,而std::forward转换后因为没有变为右值,则调用复制构造函数,与初衷背离。
  3. 清晰:std::move的含义时无条件强制转换,std::forward的含义是仅对实参是右值引用时才强制转换。

要点速记

  • std::move实施的是无条件的向右值型别的强制转换,就其本身而言,它不会执行移动操作。
  • 仅当传入的实参被绑定到右值时,std::forward才针对该实参实施向右值性别的强制转换。
  • 在运行期间,std::move和std::forward不会做任何操作。

24 区分万能引用和右值引用

万能引用:既可以是右值引用,又可以是左值引用;既可以绑定到const对象,又可以绑定非const对象;volatile对象和非volatile对象同理;甚至const和volatile同时修饰也同理。

万能引用需要具备两个条件:

  1. 必须是精确的T&&类型;
  2. 2.T的型别必须由推导而来。
// 1. 必须是精确的T&&类型
template<typename T>
void func(std::vector<T>&& param);  // 不是万能引用,是右值引用
void func(const T&& param);  // 不是万能引用,是右值引用

// 2.T的型别必须由推导而来
auto&& var2 = var1;  // 万能引用
template<typename T>
void func(T&& param);  // 万能引用

// 常见右值引用
void f(Base&& param);  // 右值引用
Base&& var1 = Base();  // 右值引用
template<typename T>
void func(std::vector<T>&& param);  // 右值引用

要点速记

  • 如果函数模板形参具备T&&型别,并且T的型别由推导而来,或如果对象使用auto&&声明其型别,则该形参或对象就是万能引用。
  • 如果型别声明并不精确地具备T&&的形式,或者型别推导并未发生,则T&&就代表右值引用。
  • 若采用右值来初始化万能引用,就会得到一个右值引用;若采用左值来初始化万能引用,就会得到一个左值引用。
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-25 11:28:13  更:2021-07-25 11:29:56 
 
开发: 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年5日历 -2024/5/3 7:45:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码