最近写程序的时候突然意识到了一个(也许大多数人早就意识到的)很常见的问题。我们知道复制一个对象(尤其是复杂的对象/实例)往往需要不小的计算开销(更别提复制一个数组的对象了)。但另一方面,复杂对象(群)的建立往往需要单独写一个函数来处理。那么如何从函数中输出这些对象?

或者看下面这个例子。

class object{
...
};object createObject( parameter ){object s( parameter );return s;
};int main(){while(...){vectors.push_back(createObject( parameter ));}
}

如果我们想在createObject函数内根据(可能动态改变的)参数parameter来构造对象,并将新建的对象填入数组中。再毫无优化的前提下,(取决于createObject的返回值类型)对象可能需要进行2次的复制构造。createObjects复制给一个临时对象作为返回值,然后该返回值在被push_backvector时再次被复制。即使我们根本不想要那么多复制出来的对象,WTF。

经验告诉我们,直接创建的对象都是保存在栈内存中的。当离开其作用域(无论因为异常还是return),堆内存会释放,这个对象也不复存在了(即使可能内存上的值不会立刻被覆盖刷新)。
一个简单的办法是将对象建立在堆上(用new关键字),并返回它的指针。但这意味着程序员必须显式地在另外的函数中对该指针调用delete方法来释放该内存避免泄漏。这很不安全,尤其在团队合作中,你的代码可能需要被另外的程序员调用。
顺着这个思路,智能指针是解决这个问题比较安全的方法。但作为一个c++程序员(而不是c程序员),总觉得不在最必要的时候使用指针显得不那么elegent(即使内部机理大同小异)。

所以说白了,我期待的是一个能建立在栈内存上,并且可以作为函数返回值(释放栈内存后仍然有效)的办法。

createObject函数内无非是进行一些构造对象的操作,对象的使用价值还是在外面体现的。所以如果只是在函数内创建的临时对象如果只是函数离开后就析构就太浪费了。我本来在想能否通过C++11提供的右值引用移动语义来获得函数的返回值所有权。

在Stack Overflow提问这个问题的时候,偶然得知了Copy Elision这个玩意。原贴在这。另外,这是个更直接的问题,以及一篇reference。

总结一下大概可以理解为,编译器发现程序员就是单纯的需要一个对象为不是其复制时,有可能会在编译阶段优化掉(也就是省略掉)这些不必要的复制。具体可以看答案下的网友给的回复(这里是复制过来的):

#include <iostream>
#include <string>
#include <vector>using Params = std::vector<std::string>;class Object
{
public:Object() = default;Object(const std::string& s) : s_{s}{std::cout << "ctor: " << s_ << std::endl;}~Object(){std::cout << "dtor: " << s_ << std::endl;}// Explicitly no copy constructor!Object(const Object& other) = delete;Object(Object&& other){std::swap(s_, other.s_);std::cout << "move: traded '" << s_ << "' for '" << other.s_ << "'" << std::endl;}Object& operator=(Object other){std::swap(s_, other.s_);std::cout << "assign: " << s_ << std::endl;return *this;}private:std::string s_;
};using Objects = std::vector<Object>;Object createObject(const std::string& s)
{Object o{s};return o;
}int main ()
{Objects v;v.reserve(4);  // avoid moves, if initial capacity is too smallstd::cout << "capacity(v): " << v.capacity() << std::endl;Params ps = { "a", "bb", "ccc", "dddd" };for (auto p : ps) {v.push_back(createObject(p));}return 0;
}

结果如下

capacity(v): 4
ctor: a
move: traded ‘a’ for ”
dtor:
ctor: bb
move: traded ‘bb’ for ”
dtor:
ctor: ccc
move: traded ‘ccc’ for ”
dtor:
ctor: dddd
move: traded ‘dddd’ for ”
dtor:
dtor: a
dtor: bb
dtor: ccc
dtor: dddd

可以发现,即便显式地禁止了复制构造函数,但该段代码仍然可以运行(虽然这里调用了移动构造函数)。我尝试了下反过来,禁用移动构造函数而启用复制构造函数,结果也是只调用了一次复制构造函数

GCC的编译选项-fno-elide-constructors可以主动关闭复制省略。

当然了,这并不是最理想的结果,因为我们还是对每个对象进行了一次没有必要的复制/移动(也就是其实建立了两倍数目的对象),但至少也减少了一次了不少么?

–如果我后面找到了可以一次复制/移动也不需要的方法会继续补充。

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. C++ Copy Elision 1

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

  5. C++ 的 Copy Elision

    Copy Elision 我们都讨厌 copy ? 如何避免 copy ? 强制性 Copy Elision 非强制性 Copy Elision 总结 我们都讨厌 copy ? 关于 copy (拷贝 ...

  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. AppStore 拒绝审核原因:PLA 2.3
  2. 打造高端网站应该具备哪些品质?
  3. Dictionary里使用struct,enum做key
  4. python 链表倒数第k个节点_链表-删除单链表中倒数第k个节点
  5. C#LeetCode刷题之#257-二叉树的所有路径(Binary Tree Paths)
  6. S3C6410 时钟初始化
  7. 力扣892.三维形体的表面积
  8. 从图(Graph)到图卷积(Graph Convolution):漫谈图神经网络模型 (一)
  9. loss低但精确度低_目标检测中的Loss改进:GIOU
  10. 内部排序算法(Golang版本)
  11. Cabbage教学(4)——面向对象编程
  12. java必背综合知识点总结(基础篇)
  13. vc 鼠标移动画直线
  14. 互联网教育已过时,教育科技才是未来的趋势
  15. pythonocc 坐标系平移
  16. What are Kernels in Machine Learning and SVM?
  17. python中的模块和类_Python模块与类
  18. Html 作业:静态页面
  19. 关于网站资源“下载”“离线”的问题 ,各位长点心吧
  20. poco mysql 安装,poco linux安装

热门文章

  1. Excel中提取单元格(括号)内的信息
  2. 独家-县域统计年鉴Excel版(2000-2021年)-包含县市及乡镇卷
  3. 新浪微博营销的方式与技巧都有哪些呢?
  4. 本地计算机 feifei pc,windows7电脑怎么设置共享打印机
  5. 存储结构和磁盘划分(基于RedHat7)
  6. pytroch冻结某些层的常用方法
  7. Hacked by 1BYTE
  8. 卷积神经网络的学习笔记1
  9. 拿到外卖后秒退单,一连12天吃霸王餐的女子栽了!
  10. Java序列中如果有些字段不想被序列化,怎么办