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++知识库 -> C++的右值引用&&研究 -> 正文阅读

[C++知识库]C++的右值引用&&研究

(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
参考:https://www.cnblogs.com/xiaobingqianrui/p/9064260.html

引言

之前总看到std::move, std::forward提供右值引用,但原理一直没有去细研究过;
想当然以为是std::move/std::forward内部识别了stl库的几种类型,提供的内部参数转移;

不过,在stl头文件看到了_Ty&&,细查一下,才发现这个是一个程序与编译器合力做的优化,并非是一个单纯编译器或程序级的优化;

如果没有定义右值引用相关的处理函数,用std::move/std::forward,全当是没用;

如果定义了右值引用相关的处理函数,没有做右值引用类型的转换,也全当是没用;

同时定义了右值引用相关的处理函数,同时调用函数时,参数做了右值引用类型转换,这样才可以用到右值引用函数的处理。

所以来说,觉得右值引用是一个编译器与程序合力配合的一个优化。

右值引用

在做变量复制或赋值的时候,指针类型转给另一个,而不进行复制的理念一直是有的;

不过对于语法层面支持,在stl库中添加容器的支持转移支持,是在c++11之后通过&&扩展用法支持的。

关于stl右值引用使用:

  1. 对于stl的相关类型的话,例如std::string,都是已经定义了右值引用的处理函数的,直接做参数右值类型转换使用就可以了。
  2. 结构体内带了std::string,std::vecotr变量的,结构体虽然没有定义右值引用处理函数;但赋值时使用了右值引用,编译器对结构体内变量仍会做右值引用赋值处理;

&&之前是代表逻辑运算的与;
不过c++11之后,在与变量类型放一起时_Ty&& 时用来识别右值引用;
&&由程序中来支援编译器右值引用的识别;

样例

例如程序这么写:即提供右值引用copy,也提供普通copy
struct Data {
void* pData;
char type;
size_t size;
Data() {
Reset();
}
void TryFree() {
if (pData != nullptr) {
delete pData;
Reset();
}
}
void Reset() {
pData = nullptr;
size = 0;
type = 0;
}
};

void CopyData(Data& dest, Data&& src) {
printf(“Copy data with right reference\n”);
dest.TryFree();
dest = src;
src.Reset();
};

void CopyData(Data& dest, const Data& src) {
printf(“Copy data normal\n”);
dest.TryFree();
dest.pData = new char[src.size];
memcpy(dest.pData, src.pData, src.size);
dest.size = src.size;
dest.type = src.type;
};

下面的方法可以使用到右值引用的函数处理:

// 调用时这样调用
CopyData(dest, std::move(src));

// 也可以这样调用
CopyData(dest, std::forward(src));

// 还可以这样调用
CopyData(dest, static_cast<Data&&>(src));

// 还可以这样调用
CopyData(dest, (Data&&)(src));

// 还可以这样调用,像std::move一样带remove_reference,为stl库提供引用去除
static_cast<std::remove_reference_t&&>(src);

代码解析

从上面可以看出,核心处理是类型转换为(_Ty&&)右值引用类型,这个类型由编译器识别的,代码就看不到了;

不过std::move,std::forward的代码可以看一下,一看究竟,是怎么转成&&类型的;

std::move不但做了类型转换,还附带做了针对stl添加转换类型remove_reference_t:
// FUNCTION TEMPLATE move
template_NODISCARD constexpr remove_reference_t<_Ty>&&
move(_Ty&& _Arg) noexcept
{ // forward _Arg as movable
return (static_cast<remove_reference_t<_Ty>&&>(_Arg));
}

std::forward做的类型转换,转换为右值引用类型,和自己写类型转换也是一样的:
// FUNCTION TEMPLATE forward
template _NODISCARD constexpr _Ty&&
forward(remove_reference_t<_Ty>& _Arg) noexcept
{ // forward an lvalue as either an lvalue or an rvalue
return (static_cast<_Ty&&>(_Arg));
}
template _NODISCARD constexpr _Ty&&
forward(remove_reference_t<_Ty>&& _Arg) noexcept
{ // forward an rvalue as an rvalue
static_assert(!is_lvalue_reference_v<_Ty>, “bad forward call”);
return (static_cast<_Ty&&>(_Arg));
}

看完发现,不光做了强制类型转换,还做了stl库的remove_reference_t引用类型识别;
从这个角度来说
a. stl库类型的右值引用,使用std::move/std::forward比较保险一点;
b. 如果自定义类型的话,就随便了,强制转换也好,使用std::move/forward也好,都ok。

(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-19 07:48:45  更:2021-09-19 07:49:04 
 
开发: 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 22:59:55-

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