【问题标题】:RVO on different compilers when using containers使用容器时不同编译器上的 RVO
【发布时间】:2020-04-22 22:12:23
【问题描述】:

我在 c++17 上有以下代码

template<typename T>
std::vector<T*> getPointerVector(std::vector<T> base) {
  auto out = std::vector<T*>();
  for (auto& t : base) {
      out.push_back(&t);
  }
  return out;
}

据我了解,RVO 应该启动并防止对返回的向量进行任何复制。但是,当我使用 GCC 时,一切正常,使用 msvc 时却不行,并且实际上复制了向量。有什么解释吗?谢谢!

编辑: 当我调试时,我确保函数内部和调用端的向量在内存中的引用是相同的。这对于 debian 测试上的 gcc 8.3 是正确的,而对于 Visual Studio 19.4 上的 msvc 则不是这样

【问题讨论】:

  • 你是如何推断它被复制的?你确定它没有被移动吗?
  • 您确实意识到您正在按值获取向量参数,并且实质上返回了一个悬空指针数组......同样,不相关:第一行最好写std::vector&lt;T*&gt; out;可能更有利于优化。
  • 具体说明您正在使用哪些工具链。在不同的平台上,GCC 和 Visual Studio 都有很多很多版本。
  • 如果你最终没有得到悬空指针,那是优化的意外。如果您不通过引用将向量传递给函数,则确实存在未定义的行为。
  • 否则,您的向量在返回时至少应移出函数(假设 C++11)。

标签: c++ gcc visual-c++ rvo


【解决方案1】:

显然您的 Visual Studio 版本并没有这样做。

或者……

当我调试时,我确保内存中的引用对于函数内部和调用端的向量是相同的。这对于 debian 测试上的 gcc 8.3 是正确的,而对于 Visual Studio 19.4 上的 msvc 则不是这样

如果您正在调试,大概是在进行调试构建,而优化通常不那么激烈。所以可能只是你把它关掉了。

它至少会移动向量,就是这样。

顺便说一句,您返回的向量的每个元素都是一个悬空指针。您的意思是引用base 吗?此外,out.reserve(base.size()) 电话也不会受到伤害。

【讨论】:

  • NRVO 在 C++17 中不是强制性的。并且 OP 使用(命名)变量。
猜你喜欢
  • 1970-01-01
  • 2012-05-18
  • 1970-01-01
  • 2021-12-10
  • 1970-01-01
  • 2021-10-03
  • 2011-02-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多