15

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

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

    return report;
}

那么我是否真的可以期望做出“最佳”选择是否将返回的字符串与移动语义一起使用,如

const std::wstring report(std::move(build_report()));

或者我是否应该依靠 (N)RVO 与

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

甚至将 const 引用绑定到临时

const std::wstring& report(build_report());

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

编辑 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;
}

两个最有趣的结果:

  • 明确要求std::move使用report1移动构造函数会使指令计数增加三倍。
  • 正如 James McNellis 在下面的回答中所指出的那样report2并且report3确实生成了相同的程序集,其指令比显式调用少 3 倍std::move
4

3 回答 3

13

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

另外,当您返回一个局部变量时,如果它是具有移动构造函数的类型,它会被移动,因此不会复制,句号。

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

于 2011-06-30T08:04:29.340 回答
4

我不确定这是否是标准化的(正如 Nicol 所说,所有优化都取决于编译器),但我听说STL谈到了这一点,并且(至少在 MSVC 中),RVO 发生其他任何事情之前。因此,如果有机会应用 RVO,那么您无需采取任何行动即可实现。其次,当您返回一个临时值时,您不必编写std::move(我认为这实际上是在标准中),因为返回值将被隐式地视为右值。

结果是:不要怀疑编译器,只需编写看起来最自然的代码,它就会给你最好的结果。

于 2011-06-30T10:09:16.083 回答
3

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

没有,也永远不会有。

编译器不需要进行任何类型的优化。你唯一能做的就是编译一些代码,看看另一端会出现什么。

您最终将获得的最多的是一般启发式,社区共识,人们说,“对于大多数编译器来说,X 似乎工作得最快。” 但仅此而已。随着编译器跟上 C++0x 的速度并实现成熟,这将需要数年时间。

于 2011-06-30T08:11:43.073 回答