首页 > 编程语言 >Effective Modern C++(四)再探移动语义与完美转发

Effective Modern C++(四)再探移动语义与完美转发

时间:2023-06-04 19:12:44浏览次数:49  
标签:推导 Effective fwd Modern C++ 完美 转发 操作 移动

  • 移动语义

移动语义是c++11最为重要的特性之一,但这不代表着我们可以在任何时候都无脑地使用它。

在以下几个情况下,移动语义并没有什么用处。

  1. 没有移动操作:要移动的对象没有提供移动操作,所以移动的写法也会变成复制操作。

比如对于STL库中的array容器而言,他的元素都直接存储在了对象当中,并没有一个指向数组首个元素的指针用来进行移动操作。

在这种情况下,即使利用move函数将他强制转换为一个右值对象,也无法进行移动操作。

  1. 移动不会更快:要移动的对象提供的移动操作并不比复制速度更快。

std::string提供了常数时间的移动操作和线性时间的复制操作。这听起来移动比复制快多了,但是可能不一定。

许多字符串的实现采用了小字符串优化(small string optimization,SSO)。

“小”字符串(比如长度小于15个字符的)存储在了std::string的缓冲区中,并没有存储在堆内存,移动这种存储的字符串并不必复制操作更快。

  1. 移动不可用:进行移动的上下文要求移动操作不会抛出异常,但是该操作没有被声明为noexcept

标准库中的某些容器操作提供了强大的异常安全保证,确保依赖那些保证的C++98的代码在升级到C++11且仅当移动操作不会抛出异常,从而可能替换操作时,不会不可运行。

结果就是,即使类提供了更具效率的移动操作,而且即使移动操作更合适(比如源对象是右值),编译器仍可能被迫使用复制操作,因为移动操作没有声明noexcept

  • 完美转发

完美转发并不完美,它不能保证总是正确无误地转发对象。

当模板类型推导失败或者推导出错误类型,完美转发会失败。

template<typename T>
void fwd(T&& param)             //接受任何实参
{
    f(std::forward<T>(param));  //转发给f
}

模版类型推导失败导致无法转发很好理解,推导出错误类型也会失败则是因为

给定我们的目标函数f和转发函数fwd,如果f使用某特定实参会执行某个操作,但是fwd使用相同的实参会执行不同的操作,完美转发就会失败。

对于推导错类型,“错误”可能意味着fwd的实例将无法使用推导出的类型进行编译,

但是也可能意味着使用fwd的推导类型调用f,与用传给fwd的实参直接调用f表现出不一致的行为。

这种不同行为的原因可能是因为f是个重载函数的名字,并且由于是“不正确的”类型推导,在fwd内部调用的f重载和直接调用的f重载不一样。

请记住:

  • 当模板类型推导失败或者推导出错误类型,完美转发会失败。
  • 导致完美转发失败的实参种类有花括号初始化,作为空指针的0或者NULL,仅有声明的整型static const数据成员,模板和重载函数的名字,位域。
 

标签:推导,Effective,fwd,Modern,C++,完美,转发,操作,移动
From: https://www.cnblogs.com/icecreamjn/p/17456126.html

相关文章

  • QT--C++简学
    2.1C++语言的新特点(对于C语言来说) 赋值:直接------- intx(100) 在定义的时候就可以赋值,相当于x=100;2.2输入(cin)--------输出(cout)  2.2.1   cout<<x<<endl;  //一个变量             --------printf     cout<<x<......
  • Effective Modern C++(三)引用折叠
    template<typenameT>voidfunc(T&&param);对于一个通用引用,只有当实参被用来实例化通用引用形参时,才会推导形参T。编码机制是简单的。当左值实参被传入时,T被推导为左值引用。当右值被传入时,T被推导为非引用。WidgetwidgetFactory();//返回右值的函数Widgetw;......
  • C++学习资源
    项目STL网站zouxiaohang/TinySTL:TinySTLisasubsetofSTL(cutsomecontainersandalgorithms)andalsoasupersetofSTL(addsomeothercontainersandalgorithms)https://github.com/zouxiaohang/TinySTL......
  • C/C++数据结构设计题[2023-06-04]
    C/C++数据结构设计题[2023-06-04]停车场模拟管理程序的设计与实现1.设计目的理解线性表的逻辑结构和存储结构,进一步提高使用理论知识指导解决实际问题的能力。2.问题描述设停车场只有一个可停放几辆汽车的狭长通道,只有一个大门可供汽车进出。汽车在停车场内按车辆到达的先后顺......
  • C++面试八股文:struct、class和union有哪些区别?
    某日小二参加XXX科技公司的C++工程师开发岗位5面:面试官:struct和class有什么区别?小二:在C++中,struct和class的唯一区别是默认的访问控制。struct默认的成员是public的,而class的默认成员是private的。面试官:struct、class和union有哪些区别?小二:union和struct、class在内存布局上......
  • Effective Modern C++(二)完美转发与移动语义
     移动语义使编译器有可能用廉价的移动操作来代替昂贵的拷贝操作。正如拷贝构造函数和拷贝赋值操作符给了你控制拷贝语义的权力,移动构造函数和移动赋值操作符也给了你控制移动语义的权力。移动语义也允许创建只可移动(move-only)的类型,例如std::unique_ptr,std::future和std::threa......
  • C++ chrono
    std::ratio表示一个单位时间。template<std::intmax_tNum,std::intmax_tDenom=1>classratio;Num是时间的分子,Denom是时间的分母。std::milli=std::ratio<1,1000>std::centi=std::<1,100>std::deci=std::<1,10>std::chrono::duration......
  • C++ java 启动器
    #include<Windows.h>#include<stdlib.h>#include<string>intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRlpCmdLine,intnShowCmd){//设置环境变量java_homestd::wstringjava_home=L"D:\\Tools\\jdk\......
  • c++函数调用压栈过程
    c++函数调用,栈内情况如下图所示:首先主函数将被调函数所需参数从右至左压入栈中然后再将主函数地址即返回地址EIP压入栈中再将主函数栈基址EBP压入栈中,此时构造被调函数栈,将当前ESP值mov给EBP,即被调函数栈从此处开始上图ida反汇编代码,可以看到对变量的使用,参数(argc,argv,env......
  • C++面试八股文:指针占用多少个字节?
    某日小二参加XXX科技公司的C++工程师开发岗位4面:面试官:memset、memcpy和strcpy的区别是什么?小二:memset用于将一块内存设置为特定的值,memcpy用于将一块内存从一个位置复制到另一个位置,strcpy用于将一个字符串从一个位置复制到另一个位置。面试官:嗯,不错。那么你知道这三个函......