Copy Elision

  • 我们都讨厌 copy ?
  • 如何避免 copy ?
    • 强制性 Copy Elision
    • 非强制性 Copy Elision
  • 总结

我们都讨厌 copy ?

关于 copy (拷贝) 是我们 C++ 开发者老生常谈的话题,对于 copy 的态度更是能免则免。不必要的拷贝除了会降低程序的性能,还会引发各种令人意想不到的问题,例如 C++ 的 Rule-of-Three 就是关于 C++ 的 copy 的另一个热议话题。

如何避免 copy ?

在 C++ 的世界里,一个对象可以有两种传递方式。一是 pass-by-value (值传递),另一个是 pass-by-address/reference (引用传递) 适用于指针或者引用 。一般我们讨论传递方式是基于把参数传入函数内部。今天我要讨论的 Copy Elision (拷贝消除),简称为 CE, 既涉及函数参数传递,又涉及函数返回值返回。需要注意的是,我对 CE 展开的讨论是基于 C++ 17 版本之前。

CE 在不同的语境下触发的条件也有所不同,分为 Mandatory Elision of Copy (强制性拷贝消除)Non-Mandatory Elision of Copy (非强制性)

强制性 Copy Elision

定义 class Widget ,为了验证函数的调用,在函数体里打印文本。

class Widget
{public:Widget() { std::cout << "ctor \n"; }Widget(const Widget& other) { std::cout << "copy ctor \n"; }Widget& operator = (const Widget& other) { std::cout << "copy assignment \n"; return *this; }
};

我以前会认为如果用一个对象去接函数 func() 的返回值会调用 Widget::(const Widget&) ,但实际上并非如此。是否会调用拷贝构造函数取决于返回值的 category (类别) 。显然函数 func() 的返回值 Widget() 的类别是 prvalue (纯右值) 并且 type (类型)Widget 必须触发强制性拷贝消除。我们称这种为 RVO (return value optimization) 。

所以在 operator= 的右边,无论嵌套多少层 Widget::Widget() 始终只会调用一次构造函数,零拷贝。

Widget func()
{return Widget();  // rvalue
}int main()
{auto obj = Widget(Widget(Widget(func());
}

非强制性 Copy Elision

在某些特定的环境下,编译器允许拷贝消除,但不一定会利用拷贝消除。我们不妨改写一下函数 func() 。函数 func() 的返回值再也不是一个 prvalue (纯右值) ,而是一个 lvalue (左值) 。这称为 NRVO (named return value optimization)。

这次程序调用了一次 Widget::Widget() 和一次 Widget::(const Widget&)。无论如何至少进行了一次拷贝。

Widget func()
{Widget w;  // lvaluereturn w; // 输出 ctor
}int main()
{auto widget = Widget(Widget(Widget(func()); // 输出 copy ctor
}

总结

这里只是对 Copy Elision 进行了简单的介绍。CE 涉及的情况太多,在不同版本的 C++ 的表现又不一样。如果想要深入 CE 的话,不妨参考 Copy elision 这个页面并且在自己的机器上运行。

C++ 的 Copy Elision相关推荐

  1. C++ Copy Elision

    故事得从 copy/move constructor 说起: The default constructor (12.1), copy constructor and copy assignment ...

  2. c++的复制省略(copy elision)

    学习 A simple C++11 Thread Pool 时,发现函数返回了std::future,而std::future的拷贝构造和拷贝赋值都是delete的,感觉有点怪,查了一下,看到 编译器 ...

  3. 有保证的复制消除(Guaranteed Copy Elision)

    作者:Jonas Devlieghere 原文地址:https://jonasdevlieghere.com/guaranteed-copy-elision/ 新的 C++ 17 标准带来了很多令人兴 ...

  4. Copy Elision

    最近写程序的时候突然意识到了一个(也许大多数人早就意识到的)很常见的问题.我们知道复制一个对象(尤其是复杂的对象/实例)往往需要不小的计算开销(更别提复制一个数组的对象了).但另一方面,复杂对象(群) ...

  5. C++ Copy Elision 1

    故事得从 copy/move constructor 说起: The default constructor (12.1), copy constructor and copy assignment ...

  6. std::move使用不当引起的copy elision

    在使用sonarqube检测C++项目代码时,发现一个使用std::move引起的code smell等级的告警,特记录. 原文内容: Usually, when copying an object, ...

  7. C++ - Copy Elision

    Copy Elision C++11/14/17编译器优化:省略不必要的拷贝 至少包括以下两项内容: 返回值优化(RVO),即通过将返回值所占空间的分配地点从被调用端转移至调用端的手段来避免拷贝操作. ...

  8. 浅谈C++11标准中的复制省略(copy elision,也叫RVO返回值优化)

    严正声明:本文系作者davidhopper原创,未经许可,不得转载. C++11以及之后的C++14.17标准均提出一项编译优化技术:复制省略(copy elision,也称复制消除),另外还有RVO ...

  9. C++17之省略不必要的拷贝Copy Elision

    从C++发展历史看来,c++ 17引入了一个规则,要求在满足一定的条件下避免对象的复制,这在以前是可选的.C++17中一个叫做强制复制省略的技术就是基于这个观点的. 至少包括以下两项内容: 1. 返回 ...

最新文章

  1. 图像降维之MDS特征抽取方法
  2. EditText中的几个常用属性
  3. 【文本分类】Convolutional Neural Networks for Sentence Classification
  4. 【Android 逆向】ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )
  5. Zookeeper集群搭建(配置详解)
  6. 猫都能学会的Unity3D Shader入门指南(一)
  7. thinkphp6 加载第三方类库_thinkphp中第三方类引入问题
  8. cogs 1111. 最短路
  9. 家长或孩子图像的Gif动画小人在少儿学习软件中的妙用.
  10. 软件工程毕设项目 - 基于SSM的房屋租赁系统(含源码+论文)
  11. 纯前端表格控件SpreadJS——轻松搞定数据绑定
  12. ExoPlayer+FFMpeg软解
  13. 2020杭州区块链国际周圆满闭幕,这一份金句集锦不能错过
  14. Linux编程经典实例,PyQt4 精彩实例分析 - 实例1 Hello Kitty! _Linux编程_Linux公社-Linux系统门户网站...
  15. OSS定制自定义response header
  16. python运行excel宏_从python运行excel宏
  17. 用加密锁实现网站身份认证
  18. 日志瘦身神操作:从5G优化到1G到底是怎么做到的!(荣耀典藏版)
  19. MUI增加BeeCloud支付集成示例
  20. 阿里云服务器能做什么呢?

热门文章

  1. 知物由学 | AI与黑产的攻守之道,详解攻击类文字图像的检测
  2. 乔巴机器人 番外篇_乔巴机器人五只合体图+10个小乔巴+【附合体动图】
  3. 技术科普丨平台效果调试篇1—灰区和权重
  4. 信创办公–基于WPS的EXCEL最佳实践系列 (筛选重要数据)
  5. 白骨精写给孙悟空的信
  6. Unity3D RectTransform中文图文详细-anchors用法pivot分析
  7. 手机抓包获取数据,ROOT权限获取,xian鱼,taobao
  8. POJ2248 Addition Chains(迭代加深搜索)
  9. php获取汉字个数,获取文件中汉字个数
  10. Log4j2报错ERROR StatusLogger Unrecognized format specifier