栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

c++ std::move和std::forward总结与使用

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c++ std::move和std::forward总结与使用

右值和左值的区别:

当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)。左值与右值的根本区别在于是否允许取地址&运算符获得对应的内存地址。
C++/C++11中左值、左值引用、右值、右值引用的使用

std::move解析

std::move的唯一功能就是将一个左值引用强制转化为右值引用

	std::string str = "hello";
    std::vector v;
    //调用拷贝构造函数
    v.push_back(str);
    //调用移动构造函数,掏空str,掏空后,不可以再使用str
    v.push_back(std::move(str));
std::move源码解析

std::move的函数原型定义:

template 
typename remove_reference::type&& move(T&& t)
{
	return static_cast::type &&>(t);
}

首先函数参数T&&是一个指向T类型的右值引用,通过引用折叠,将T&&传递过来的类型,右值保持不变,左值变成普通的左值引用,然后在通过remove_reference::type模板移除T&&,T&的引用,获取到具体的类型T

//原始的,最通用的版本
template  struct remove_reference{
    typedef T type;  //定义T的类型别名为type
};
 
//部分版本特例化,将用于左值引用和右值引用
template  struct remove_reference //左值引用
{ typedef T type; }
 
template  struct remove_reference //右值引用
{ typedef T type; }   
  
//举例如下,下列定义的a、b、c三个变量都是int类型
int i;
remove_refrence::type a;             //使用原版本,
remove_refrence::type  b;             //左值引用特例版本
remove_refrence::type  b;  //右值引用特例版本 

引用折叠,其实就是多个引用的意思,所有的引用折叠最终都代表一个引用,要么是左值引用,要么是右值引用
规则就是:
如果任一引用为左值引用,则结果为左值引用,否则为右值引用
比如 int& &&等价于int &
这个的应用场景主要为函数模板的推导
https://zhuanlan.zhihu.com/p/50816420

std::forward解析

在任何的函数内部,对形参的直接使用,都是按照左值进行的,比如:

template
void func(T& t){
   std::cout<<"func(T& t)"<
void func(T&& t){
    std::cout<<"func(T&& t)"<
void printType(T&& t){
    func(t);
}
int main()
{
    int  i = 0;
    printType(i);
    printType(2);
}

这段代码的打印为:

func(T& t)
func(T& t)

那我们要怎么让调用的函数按我们的预期执行呢,答案就是使用std::forward:

template
void printType(T&& t){
    func(std::forward(t));
}

打印为:

func(T& t)
func(T&& t)
std::forward源码解析
template 
_Tp&&
forward(typename remove_reference<_Tp>::type& __t) _NOEXCEPT
{
    return static_cast<_Tp&&>(__t);
}

template 
_Tp&&
forward(typename remove_reference<_Tp>::type&& __t) _NOEXCEPT
{
    return static_cast<_Tp&&>(__t);
}

首先通过remove_reference拿到_Tp的直接类型,如int类型

  • 对于第一个函数,通过remove_reference,t的类型是int&,再通过static_cast中的引用折叠,static_cast<_Tp& &&>,最终拿到的是左值引用
  • 对于第二个函数,通过remove_reference,t的类型是int&&,再通过static_cast中的引用折叠,static_cast<_Tp&& &&>,最终拿到的是右值引用

因此这样实现了完美转发

参考文档:
https://blog.csdn.net/daaikuaichuan/article/details/88371948

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1034947.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号