【发布时间】:2017-01-04 23:33:49
【问题描述】:
我目前正在努力使用 c++ 和 copy elision,特别是“命名返回值优化”(NRVO),以便能够实现工厂函数模式。我无法在不同的编译器中获得一致的行为。我的mwe:
#include <iostream>
struct base {
virtual ~base() { std::cout << "dtor base\n"; }
};
struct derived : public base {
~derived() { std::cout << "dtor derived\n"; }
};
derived f() { return derived(); }
int main(int argc, char *argv[]) {
std::cout << "start\n";
new derived(f());
std::cout << "done. should have leaked!\n";
}
注意:删除 virtual base-dtor 可以解决问题,但我需要它来实际实现。
在 gcc 5.4.0 的情况下,调用 dtor,不执行复制省略:
$ g++ test2.cpp && ./a.out
start
dtor derived
dtor base
done. should have leaked!
当使用 gcc 5.4.1(Ubuntu 将其称为 5.4.1,我假设这是 svn-head)时,我可以使用的所有 clang 以及各种其他 gcc 都会执行省略并成功泄漏内存:
$ g++ test2.cpp && ./a.out
start
done. should have leaked!
当我阅读 internetz 上的不同地方时,编译器允许进行复制省略,但不是必需的。只有 c++17 引入了保证复制 elision。那么这是 gcc 5.4.0 中的错误,还是只是以不同的方式实现标准?
【问题讨论】:
-
如果允许编译器优化它,但它不是必须的,它怎么可能是一个错误?
-
我将编辑问题并删除有关 gcc 中健康代码的部分 - 这部分无论如何都会偏离主题,它只会破坏主题问题。
-
当你说“成功泄露”时——你确实意识到 GCC 也在泄露内存?
f()返回的临时值被复制到 new 分配的内存中(使用复制构造函数),然后被销毁 - 这就是您看到的析构函数。 -
尝试检测复制构造函数以查看发生了什么。
-
@NathanOliver:是的,这是我的问题。所以允许编译器不省略。嗯。