【问题标题】:C++ returning an object copyC++ 返回一个对象副本
【发布时间】:2012-05-30 14:26:03
【问题描述】:

我写了以下代码:

class MyObjectHolder {
public:
    std::vector<int> getMyObject() const {
        return myObject;
    }

private:
    std::vector<int> myObject;
};

在我的程序的某个时刻,我尝试使用 getMyObject 方法,并且只对检索到的对象使用 const 方法:

const std::vector<int> myObject = myObjectHolder.getMyObject();
myObject.size();
int a = myObject.front();
  • 现在,编译器是否有可能优化此代码,以便不复制std::vector&lt;int&gt;

    编译器是否有可能确定我只在检索到的对象上使用const 方法(假设后面没有发生mutable 废话) 不会复制对象,而是对MyObjectHolderprivate 成员执行这些const 操作?

  • 如果是,如果我没有将const std::vector&lt;int&gt; myObject 明确声明为const,是否有可能?

  • 如果不是,不这样做的原因是什么?在哪些情况下,这种优化将难以实施/推断它是可能的并且在这里/等等......?

【问题讨论】:

  • RVO 涉及临时对象。除非我遗漏了什么,否则这里没有临时对象,所以没有 RVO。
  • @hmjd 对。我不应该在这里谈论RVO,而是直接使用private 变量可能进行的优化。谢谢。

标签: c++ optimization copy copy-constructor rvo


【解决方案1】:

现在,编译器是否有可能优化这段代码,使std::vector&lt;int&gt; 的副本不复存在?

不,编译器不知道调用者将对该对象做什么,除非您对使用该对象的所有代码使用全局优化(编译器通常不能对其使用做出假设;此外,如果对象是从 dll 导出,它根本无法做出任何假设)。

如果是,如果我没有将 const std::vector myObject 显式声明为 const,是否有可能?

不,无论如何,从非常量到常量的转换可能是隐式的。

如果不是,不这样做的原因是什么?在哪些情况下,这种优化将难以实现/推断它是可能的并且在这里/等等......?

这是一个应该在 getMyObject() 内部完成的优化,但编译器不能确定调用者不会丢弃 const。实际上,这是关于const 使用的一个非常古老的争论,通常我认为始终将const 视为程序员而不是编译器的东西会更清楚。

【讨论】:

  • “不,编译器不知道调用者将如何处理该对象。” -> 一般不正确。提议的更改:“除非您对对象的所有代码使用全局优化,否则编译器通常无法做出假设”或类似内容。
  • @phresnel 你是对的(已编辑),此外,如果对象被导出,它就无法做出任何假设(而且我不确定它甚至可以跟随同一单元内的演员表)。
  • 更重要的是,编译器可以输出同一个函数的多个版本,这意味着更通用的编辑:P
  • 附带说明:我认为如果操作系统能够提供一个系统调用来复制写入时复制的数据,那就太好了。 IE。告诉操作系统“在我的进程中获取这部分地址空间,并将其镜像到那里,但如果我写入它,则制作原位修改副本。”大多数操作系统中已经存在为此的基础设施,只需要一个新的系统调用来公开此功能。嗯…….oO(cd /usr/src/linux/ ; vim … ;)
  • @Adriano:我不认为这是编译器需要处理的事情。传递向量而不进行复制的 OP 请求也可以在库中实现(保持对原始向量的引用并且仅在调用非常量函数进行复制时)。现在在这样一个基于库的实现中,您必须完成一个完整的副本,如果只更改几个元素,这不是很有效。库可以通过像“memcow”这样的系统调用将 CoW 副本创建到新的向量对象中。在那里修改会使它成为一个真正的副本,否则只是参考
【解决方案2】:

我建议使用

const std::vector<int>& getMyObject() const {
    return myObject;
}

它将返回 myObject 的常量引用而不复制它。

并将结果与​​

一起使用
const std::vector<int>& myObject = myObjectHolder.getMyObject();

【讨论】:

    【解决方案3】:

    Copy ElisionReturn Value Optimization 可能会启动。如果您使用支持 C++11 的 C++ 编译器,那么您可能会通过 move semantics 对其进行优化。

    我建议阅读 Dave Abrahams 的优秀文章 Want Speed? Pass by Value,并在其下方的 cmets 中进行讨论。

    但是,有关详细信息,您应该参考 C++ 编译器的文档。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-21
      • 1970-01-01
      • 2019-07-24
      • 2020-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多