强制复制省略?通用条款5.4.1 我目前正在与C++和特定的“命名返回值优化”(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"; }

强制复制省略?通用条款5.4.1 我目前正在与C++和特定的“命名返回值优化”(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"; },c++,c++11,gcc,C++,C++11,Gcc,当使用gcc 5.4.1(Ubuntu称之为5.4.1,我假设这是svn head)时,我能接触到的所有叮当声以及各种其他gcc执行省略并成功泄漏内存: $ g++ test2.cpp && ./a.out start done. should have leaked! 当我在internetz上阅读不同的地方时,编译器可以进行复制省略,但不是必需的。只有c++17引入了保证拷贝。那么,这是gcc 5.4.0中的一个缺陷,还是只是以不同的方式实现了该标准?在C++17之前,复

当使用gcc 5.4.1(Ubuntu称之为5.4.1,我假设这是svn head)时,我能接触到的所有叮当声以及各种其他gcc执行省略并成功泄漏内存:

$ g++ test2.cpp  && ./a.out
start
done. should have leaked!

当我在internetz上阅读不同的地方时,编译器可以进行复制省略,但不是必需的。只有c++17引入了保证拷贝。那么,这是gcc 5.4.0中的一个缺陷,还是只是以不同的方式实现了该标准?

在C++17之前,复制省略是可选的优化,即使在C++17中,它也只是在某些情况下是强制性的。就我所记得的,(N)即使在C++17中,RVO拷贝省略也不是强制的-唯一强制的拷贝省略情况是使用临时的初始化

(N) RVO不应改变程序的行为,也不应要求程序正常运行。您应该以这样一种方式编写代码,即无论(N)RVO如何,它都能正常工作,并且在/if(N)RVO启动时工作得更快

在gcc 5.4.0的情况下,调用dtor时,不执行复制省略:

$ g++ test2.cpp && ./a.out
start
dtor derived
dtor base
done. should have leaked!
start
dtor derived
dtor base
done. should have leaked!
实际上,执行了拷贝省略。否则你会看到

start
dtor derived
dtor base
dtor derived
dtor base
done. should have leaked!
这里有两个省略复制的机会。一个是
f
中的RVO(注意,它不是NRVO,只是常规的未命名RVO),另一个是从临时文件中导出的
*的副本构造。GCC 5.4.0执行了一个可能的副本省略

全部。。。执行删除并成功泄漏内存

GCC 5.4.0还成功地泄漏了
derived
所指向的内存。其他编译器从未创建过5.4.0所创建的临时文件,后来被销毁

当我阅读internetz上的不同位置时,编译器可以执行复制省略,但不是必需的

那么这是gcc 5.4.0中的一个bug吗


不。不总是实现拷贝省略的编译器符合标准。请参阅我之前引用的问题中突出显示的部分。

如果允许编译器对其进行优化,但它不必进行优化,那么它怎么会是一个bug呢?我将编辑该问题并删除关于gcc中健康代码的部分-这部分无论如何都是非主题的,它只是对主题问题的重击。当您说“成功泄漏”-您确实意识到GCC也在泄漏内存吗?
f()
返回的临时文件正在复制到new(使用复制构造函数)分配的内存中,然后销毁-你看到的就是这个析构函数。试着检测复制构造函数,看看发生了什么。@NathanOliver:是的,这是我的问题。所以编译器不允许省略.Hmpf。正如我所读到的,复制省略可以改变程序行为:它是省略的唯一优化形式(哈!)即使复制/移动对象有副作用,也可以应用“仿佛”规则-复制省略。@fdgsydfgsdfgsdfg要澄清,(N)如果程序依赖于临时性和副作用的产生,RVO可以改变程序的行为。SergeyA的观点是,您的程序永远不应该依赖这些副作用,如果它不依赖,(N)RVO不会改变行为。是的,依赖复制省略是个坏主意…我得到了这个;-)执行了省略:你是对的。使用
-fno elide构造函数调用gcc会产生两倍的消息…哈。。。