什么时候C++ 11编译器会使RVO和NRVO表现优于移动语义和const引用绑定?

Joh*_*ell 15 c++ optimization reference move-semantics c++11

考虑从函数返回启用了移动语义的"整个"对象的情况,如std::basic_string<>:

std::wstring build_report() const
{
    std::wstring report;
    ...

    return report;
}
Run Code Online (Sandbox Code Playgroud)

然后我可以真实地期望做出"最佳"选择是否使用带有移动语义的返回字符串,如

const std::wstring report(std::move(build_report()));
Run Code Online (Sandbox Code Playgroud)

或者我是否应该依赖(N)RVO来进行

const std::wstring report(build_report());
Run Code Online (Sandbox Code Playgroud)

甚至将const引用绑定到临时用

const std::wstring& report(build_report());
Run Code Online (Sandbox Code Playgroud)

有什么方案可以确定性地选择这些选项,如果有的话?

编辑1:请注意,std::wstring上面的用法只是移动语义启用类型的一个示例.它也可以换成你的arbitrary_large_structure.:-)

编辑2:我在VS 2010中运行以下速度优化版本时检查生成的程序集:

std::wstring build_report(const std::wstring& title, const std::wstring& content)
{
    std::wstring report;
    report.append(title);
    report.append(content);

    return report;
}

const std::wstring title1(L"title1");
const std::wstring content1(L"content1");

const std::wstring title2(L"title2");
const std::wstring content2(L"content2");

const std::wstring title3(L"title3");
const std::wstring content3(L"content3");

int _tmain(int argc, _TCHAR* argv[])
{
    const std::wstring  report1(std::move(build_report(title1, content1)));
    const std::wstring  report2(build_report(title2, content2));
    const std::wstring& report3(build_report(title3, content3));

    ...

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

最有趣的两个结果:

  • 显式调用std::movereport1使用移动构造函数三倍的指令数.
  • 正如James McNellis在下面的回答中所指出的那样,report2并且report3确实生成相同的汇编,指令比明确调用的指令少3倍std::move.

Jam*_*lis 13

std::move(build_report())完全没必要: build_report()已经是一个rvalue表达式(它是一个按值返回一个对象的函数的调用),所以std::wstring如果它有一个(它确实),那么将使用移动构造函数.

另外,当您返回一个局部变量时,如果它是一个具有移动构造函数的类型,它将被移动,因此不会创建副本,句点.

声明report为对象或const-reference 之间不应存在任何功能差异; 在这两种情况下,您最终都会得到一个对象(命名report对象或report可以绑定引用的未命名对象).