我有以下代码:(好吧,实际上它要复杂得多,但我简化了它以使其更容易理解。所以请忽略那些看似愚蠢的东西。我无法根据实际情况更改它们)
#include <string>
using std::string;
ReportManager g_report_generator;
struct ReportManager
{
// I know, using c_str in this case is stupid.
// but just assume that it has to be this way
string GenerateReport() { string report("test"); return report.c_str(); }
}
string DoIt(bool remove_all)
{
if(g_report_generator.isEmpty())
return string();
string val = g_report_generator.GenerateReport();
if(remove_all)
g_report_generator.clear();
return val;
}
void main()
{
string s = DoIt(true);
}
我的函数会应用 (N)RVO 吗? 我做了一些研究,看起来是这样,但我不太相信,我想要第二个意见(或更多)。
我使用的是 Visual Studio 2017。
最佳答案
为了解决您的问题,我重写了它。
#include <string>
struct string : std::string {
using std::string::string;
string(string&& s) {
exit(-1);
}
string(string const&) {
exit(-2);
}
string() {}
};
struct ReportManager
{
// I know, using c_str in this case is stupid.
// but just assume that it has to be this way
string GenerateReport()
{
string report("test");
return report.c_str();
}
bool isEmpty() const { return true; }
void clear() const {}
};
ReportManager g_report_generator;
string DoIt(bool remove_all)
{
if(g_report_generator.isEmpty())
return string();
string val = g_report_generator.GenerateReport();
if(remove_all)
g_report_generator.clear();
return val;
}
int main()
{
string s = DoIt(true);
}
这种重写的诀窍是省略允许跳过复制/移动函数。所以每次我们实际复制一个对象时(即使是内联的),我们都会插入一个 exit
子句;只有省略才能避免。
GenerateReport
没有 (N)RVO 或任何类型的省略,除非可能在 as-if 下。我怀疑编译器是否能够证明这一点,尤其是当字符串是非静态字符串并且大到需要堆存储时。
对于 DoIt
,NRVO 和 RVO 都是可能的。省略在那里是合法的,即使有副作用。
MSVC fails --通知调用
??0string@@QAE@$QAU0@@Z
,这是我本地 string
类的移动构造函数。
当我强制运行可能的 RVO 案例时 by saying it is empty ,你会看到编译器在这里也无法进行 RVO 优化;反汇编中内联了一个 exit(-1)
。
Clang设法 RVO return string();
但不是 NRVO return val;
。
到目前为止,最简单的修复是:
string DoIt(bool remove_all)
{
if(g_report_generator.isEmpty())
return string();
return [&]{
string val = g_report_generator.GenerateReport();
if(remove_all)
g_report_generator.clear();
return val;
}();
}
它有双 RVO 和一个执行简单 NRVO 的 lambda。对您的代码和 C++98 编译器可以省略返回值的函数进行零结构更改(好吧,它们不支持 lambda,但您明白了)。
关于c++ - 在这种情况下,我的函数会应用 (N)RVO 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54333687/