繁体   English   中英

我应该将ref或副本分配给值返回函数吗?

[英]Should I assign a ref or a copy to a value returning function?

我们有一堆值返回函数:

Foo function_1(){
    Foo f;
    // ...
    return f;
}

Bar function_2(){
    Bar b;
    // ...
    return b;
}

Baz function_3(){
    Baz b;
    // ...
    return b;
}

我正在使用它们来创建局部变量的实例化:

void example(){  
    //...
    const auto foo = function_1();
    //...
    const auto bar = function_2();
    //...
    const auto baz = function_3();
}

但是,我的队友一直要求我将我的所有实例转换为使用&

void example(){  
    //...
    const auto& foo = function_1();
    //...
    const auto& bar = function_2();
    //...
    const auto& baz = function_3();
}

这样做的理由似乎符合以下问题:
为什么不总是将返回值赋给const引用?

我知道auto& x =auto x =要求两个不同的东西,并且行为可能因函数的实现而有所不同。

话虽这么说,我正在寻找关于选择在返回值函数时这些差异(如果有的话)的澄清? 行为保证是否相同?

如果它是一个值返回函数,我如何在const auto& vs const auto之间做出决定? (大概const在这里没关系?)。 我在C ++核心指南中找不到任何关于此的建议。 我希望这不是一个有问题的问题。

您的同事正在尝试执行编译器的工作而不是信任它,并且可能因此而感到悲观。 NRVO得到了很好的支持,如果函数是用值语义编写的,NRVO可以省略多个副本。 绑定到引用将阻止这种情况,因为引用变量将不满足此优化的条件。 一个简单的测试来证明

#include <iostream>

struct Test {
    Test() { std::cout << "Created\n"; }
    Test(const Test&) { std::cout << "Copied\n"; }
};

Test foo() {
    Test t;
    return t;
}

Test bar_good() {
    const auto t = foo();
    return t;
}

Test bar_bad() {
    const auto& t = foo();
    return t;
}

int main() {
    const auto good = bar_good(); (void)good;

    std::cout << "===========\n";

    const auto& bad = bar_bad();  (void)bad;
}

这给出了输出:

Created
===========
Created
Copied

一个对象在使用值语义时总计,但在使用引用时是一个冗余副本。 根据复制(甚至移动)的扩展程度,您可以看到明显的性能差异。

这是我的建议:

如果您需要对函数返回的对象进行只读访问,请使用

const auto& foo = function_1();

如果您希望能够修改返回的对象,或者不希望在您不知情的情况下将某个其他功能删除该对象,请复制。

auto foo = function_1();

回复评论的其他信息

使用g++ -std=c++11 -Wall编译以下程序时

#include <iostream>

struct Foo
{
   Foo() {}
   Foo(Foo const& copy) { std::cout << "In copy constructor\n"; }
};

Foo function_1(){
    Foo f;
    return f;
}

int main()
{
   std::cout << "-------------------------\n";
   auto f1 = function_1();
   std::cout << "-------------------------\n";
   const auto& ref = function_1();
}

我得到以下输出(没有构造函数的输出)。

-------------------------
-------------------------

当使用g++ -std=c++11 -Wall -fno-elide-constructors编译相同的程序时

我得到以下输出。

-------------------------
In copy constructor
In copy constructor
-------------------------
In copy constructor

如果编译器默认情况下不支持复制省略,则在使用时会生成其他副本

auto f1 = function_1();

恕我直言 - 当你想要返回的东西引用现有对象时,你应该通过引用返回。 当您希望调用者获得与其他对象无关的副本时,您应该按值返回。

例如; 如果您有一个函数从容器返回一个对象,并且您希望调用者能够更新原始值,则返回一个引用。 如果调用者应该只使用自己的副本来处理它不应该影响容器中的原始对象,那么按值返回。

我的经验法则是值语义是最容易使用的 - 在返回对象和将它们作为参数时,所以我更喜欢按值取值/返回,除非我有明确的理由不这样做。

参考的好处是它始终是功能性的。 如果按值捕获,则复制省略可以使其像通过引用捕获一样; 但是如果删除了复制构造函数,则按值捕获会触发一次移动,然后销毁临时文件,效率会降低一些; 如果删除了移动构造函数,则编译失败。 现在,必须在mutable和const之间做出选择:如果是可变的,那么你需要可变的右值引用; 否则,const左值参考。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM