强制省略副本?gcc 5.4.1

Mandatory copy elision? gcc 5.4.1

本文关键字:gcc 制省 副本      更新时间:2023-10-16

我目前正在努力实现c++和复制省略,特别是"命名返回值优化"(NRVO),以便能够实现工厂函数模式。我无法在不同的编译器之间获得一致的行为。我的mwe:

#include <iostream>
struct base {
virtual ~base() { std::cout << "dtor basen"; }
};
struct derived : public base {
~derived() { std::cout << "dtor derivedn"; }
};
derived f() { return derived(); }
int main(int argc, char *argv[]) {
std::cout << "startn";
new derived(f());
std::cout << "done. should have leaked!n";
}

注意:删除虚拟基本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)时,我能拿到的所有clangs以及其他各种gcc都会执行省略并成功泄漏内存:

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

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

复制省略在C++17之前是一个可选的优化,即使在C++17中,它也只是在某些情况下是强制性的。据我所知,即使在C++17中,(N)RVO副本省略也不是强制性的——唯一强制性的副本省略情况是使用临时初始化。

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

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

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),另一个是从临时复制*derived的构造。GCC 5.4.0执行了一个可能的副本省略。

所有。。。执行省略并成功泄漏内存

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

当我在互联网上阅读不同的地方时,编译器可以执行复制省略,但不是必需的

正确。

那么这是gcc 5.4.0 中的一个错误吗

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