2

假设一个基本方法:

std::string StringTest()
{
    std::string hello_world("Testing...");

    return std::move(hello_world);
}

我应该如何使用输出:

选项 A:

auto& string_test_output=StringTest();

选项 B:

auto string_test_output=StringTest();

StringTest() 是临时值吗?如果是这样,选项 A 将不安全。如果不是临时值,我感觉选项 B 会导致复制。

我仍然习惯于 RValue 引用,因此按值返回仍然非常可怕,因为我不希望发生复制或遇到不必要的复制!

4

2 回答 2

3

最好的方法是将您的方法更改为:

std::string StringTest()
{
    std::string hello_world("Testing...");

    return hello_world;
}

没有必要告诉函数返回的对象应该是一个右值,这会自动来自临时值——也就是说,它在调用站点没有绑定到任何名称。因此,initialized 将值已经被移动构造(除非函数内部的临时值被完全省略),您无需手动表达这样的意图。

此外,由于您的返回类型是std::string,您将按值返回,而不是按右值引用返回,因此在返回之前移动返回参数是没有意义的。事实上,调用std::move除了可能欺骗编译器在返回值之前执行额外的不必要的移动构造函数之外没有任何作用。除了使您的代码稍微复杂一些并且运行速度可能更慢之外,这样的技巧没有任何作用。

您也确实希望按值返回。一个原因是因为返回值优化 (RVO)。大多数编译器都会这样做,这意味着你最好只返回一个被忽略的“副本”,而不是试图变得聪明并返回一个引用。

即使无法应用 RVO,通过右值引用返回它仍然不会改变它的返回方式。当返回值时,由于它是调用站点的临时值,因此返回的值将已经是一个右值,可以通过右值引用传递给任何需要它作为参数的函数。例如,如果您使用返回值来初始化变量并且返回值没有被省略,则移动构造函数仍然会被调用(如果可用)。因此,简单地按值返回并不会损失太多。

鉴于此,您可能应该执行以下操作之一来获取价值:

auto string_test_output = StringTest();
std::string string_test_output = StringTest();
于 2013-04-05T04:57:40.477 回答
0

按值返回 std::string (通常是任何可移动类型)并因此初始化新对象将永远不会触发复制构造。在最坏的情况下,它会触发移动构造,但通常由于复制省略,不会涉及运行时开销。

我推荐这篇文章来了解价值语义及其成本的背景。

于 2013-04-05T08:03:36.917 回答