我目前正在努力使用c ++和copy elision,特别是"命名返回值优化"(NRVO),以便能够实现工厂功能模式.我不能在不同的编译器中获得一致的行为.我的妈妈:
#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";
}
Run Code Online (Sandbox Code Playgroud)
注意:删除虚拟base-dtor可以解决问题,但我需要它才能实现真正的实现.
如果是gcc 5.4.0,则调用dtor,不执行复制省略:
$ g++ test2.cpp && ./a.out
start
dtor derived
dtor base
done. should have leaked!
Run Code Online (Sandbox Code Playgroud)
当使用gcc 5.4.1(Ubuntu称之为5.4.1,我认为这是svn-head)时,我可以接触到的所有clang以及各种其他gcc执行elision并成功泄漏内存:
$ g++ test2.cpp && ./a.out
start
done. should have leaked!
Run Code Online (Sandbox Code Playgroud)
当我读到internetz上的不同位置时,编译器可以进行复制省略但不是必需的.只有c ++ 17引入了有保证的复制省略.这是gcc 5.4.0中的一个错误,还是只是以不同的方式实现标准?
复制elision是一个可选的优化,直到C++ 17,甚至在C++ 17中,它只在某些情况下是强制性的.据我所知,(N)即使在C++ 17中,RVO复制省略也不是强制性的 - 唯一强制的复制省略是临时初始化.
(N)RVO永远不应该改变你的程序的行为,并且永远不需要你的程序正常运行.无论(N)RVO如何,您都应该以适当的方式编写代码,并且当/ if(N)RVO启动时,只需更快地工作.