在这种情况下,(N)RVO是否适用于我的功能
Will (N)RVO be applied with my function in this situation?
我有以下代码:(好吧,实际上它要复杂得多,但我简化了它,使其更容易理解。所以请忽略那些看起来很愚蠢的东西。我无法在实际情况下更改它们)
#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);
}
这种重写的诀窍在于省略允许跳过复制/移动actor。因此,每次我们实际复制一个对象(即使是内联的)时,我们都会插入一个exit
子句;只有省略才能避免它。
GenerateReport
不具有(N)RVO或任何类型的省略,除了可能的under as if。我怀疑编译器是否能够证明这一点,尤其是如果字符串是非静态的,并且足够大,需要堆存储。
对于DoIt
,NRVO和RVO都是可能的。Elision在那里是合法的,即使有副作用。
MSVC失败--通知调用??0string@@QAE@$QAU0@@Z
,它是我的本地string
类的移动构造函数。
当我通过说它是空的来强制运行可能的RVO情况时,你会看到编译器在这里也无法进行RVO优化;存在内联到反汇编中的CCD_ 6。
Clang设法RVOreturn string();
而不NRVO CCD_。
到目前为止,最简单的解决方案是:
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的λ。对代码和C++98编译器可以消除返回值的函数进行零结构更改(好吧,它们不支持lambda,但你已经明白了)。
我认为(N)RVO在这两个函数中都不可能。GenerateReport
必须从字符数组中构造一个字符串,NRVO已所剩无几。DoIt
通过它的控制路径返回两个不同的值,这使得无法执行NRVO。
- __attribute__(优化(0))) 是否适用于"recursively"?
- 结构化绑定是否适用于 std::vector?
- 继承函数是否适用于 C++ 中的基类元素或派生类元素?
- 多态性是否适用于值?或者在按(基)值返回时使用派生类的移动构造函数
- 如何检测运算符[]是否适用于Type
- gcc-fdiagnostics颜色是否适用于Windows
- 英特尔 tbb 任务调度是否适用于 DBMS
- C++11 正则表达式是否适用于 UTF-8 字符串
- 未定义的行为是否适用于 asm 代码
- CUDA TCC 驱动程序是否适用于 Windows 上的 geforce 卡
- HID 设备编程 - 它是否适用于C++(SETUPAPI.dll 和 HID.dll)
- 关于"distinct addresses"的规则是否适用于 new 创建的对象?
- 名称篡改是否适用于c++中的虚拟函数
- 多态是否适用于在C中传递的c++对象引用?
- 如何发现休眠是否适用于Windows用户(使用c++)
- 这个时钟是否适用于Intel i3 ?
- boost::variant是否适用于std::string
- RVO 是否适用于"new"?
- 对齐说明符是否适用于"新"?
- Poco 是否适用于 LLVM 标准C++库