简体   繁体   English

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

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

We have a bunch of value returning functions: 我们有一堆值返回函数:

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

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

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

I'm using them to create instantiations of local variables: 我正在使用它们来创建局部变量的实例化:

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

However, my teammates keep asking me to convert all my instantiations to use & : 但是,我的队友一直要求我将我的所有实例转换为使用&

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

The rationale for doing this seems to match the following question: 这样做的理由似乎符合以下问题:
Why not always assign return values to const reference? 为什么不总是将返回值赋给const引用?

I understand that auto& x = and auto x = are asking for two different things, and the behavior might be different based on the implementation of the function. 我知道auto& x =auto x =要求两个不同的东西,并且行为可能因函数的实现而有所不同。

That being said, I'm looking for clarification about the differences (if any) when choosing to do this on value returning functions? 话虽这么说,我正在寻找关于选择在返回值函数时这些差异(如果有的话)的澄清? Is the behavior guaranteed to be the same? 行为保证是否相同?

If its a value returning function how do I decide between const auto& vs const auto ? 如果它是一个值返回函数,我如何在const auto& vs const auto之间做出决定? (presumably the const doesn't matter here?). (大概const在这里没关系?)。 I couldn't find any advice about this in the C++ Core Guidelines. 我在C ++核心指南中找不到任何关于此的建议。 I'm hoping its not an opinioned question. 我希望这不是一个有问题的问题。

Your colleague is trying to do the compiler's job instead of trusting it, and is potentially pessimizing as a result. 您的同事正在尝试执行编译器的工作而不是信任它,并且可能因此而感到悲观。 NRVO is very well supported, and if the functions are written with value semantics, NRVO can elide multiple copies. NRVO得到了很好的支持,如果函数是用值语义编写的,NRVO可以省略多个副本。 Binding to a reference will prevent that, since a reference variable will not satisfy the conditions for this optimization. 绑定到引用将阻止这种情况,因为引用变量将不满足此优化的条件。 A simple test to demonstrate : 一个简单的测试来证明

#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;
}

Which gives the output: 这给出了输出:

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

One object total when utilizing value semantics, but a redundant copy when using references. 一个对象在使用值语义时总计,但在使用引用时是一个冗余副本。 Depending on how expansive the copy (or even move) is, you could see a noticeable performance difference. 根据复制(甚至移动)的扩展程度,您可以看到明显的性能差异。

This is my suggestion: 这是我的建议:

If you need read-only access to the objects returned by the functions, use 如果您需要对函数返回的对象进行只读访问,请使用

const auto& foo = function_1();

If you want to be able to modify the returned objects or don't want to take the chance that the object might be deleted by some other function without your knowledge, make a copy. 如果您希望能够修改返回的对象,或者不希望在您不知情的情况下将某个其他功能删除该对象,请复制。

auto foo = function_1();

Additional info in response to comments 回复评论的其他信息

When the following program is compiled with g++ -std=c++11 -Wall 使用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();
}

I get the following output (no output from the constructor). 我得到以下输出(没有构造函数的输出)。

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

When the same program is compiled with g++ -std=c++11 -Wall -fno-elide-constructors 当使用g++ -std=c++11 -Wall -fno-elide-constructors编译相同的程序时

I get the following output. 我得到以下输出。

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

If a compiler does not support copy elision by default, an additional copy is made when using 如果编译器默认情况下不支持复制省略,则在使用时会生成其他副本

auto f1 = function_1();

IMHO - You should return by reference when you want the thing you return to refer to an existing object. 恕我直言 - 当你想要返回的东西引用现有对象时,你应该通过引用返回。 You should return by value when you want the caller to get a copy that's unrelated to some other object. 当您希望调用者获得与其他对象无关的副本时,您应该按值返回。

For example; 例如; if you have a function returning an object from a container and you want the caller to be able to update the original value, then return a reference. 如果您有一个函数从容器返回一个对象,并且您希望调用者能够更新原始值,则返回一个引用。 If the caller should just get their own copy to work with that should not affect the original object in the container, then return by value. 如果调用者应该只使用自己的副本来处理它不应该影响容器中的原始对象,那么按值返回。

My rule of thumb is that value semantics are the easiest to work with - both when returning objects and taking them as arguments, so I prefer taking/returning by value unless I have an explicit reason not to. 我的经验法则是值语义是最容易使用的 - 在返回对象和将它们作为参数时,所以我更喜欢按值取值/返回,除非我有明确的理由不这样做。

The benefit of reference is that it is always functional. 参考的好处是它始终是功能性的。 If captured by value, copy elision may make it as if it is captured by reference; 如果按值捕获,则复制省略可以使其像通过引用捕获一样; but if copy constructor is deleted, capture by value triggers a move followed by destruction of the temporary which is a bit less efficient; 但是如果删除了复制构造函数,则按值捕获会触发一次移动,然后销毁临时文件,效率会降低一些; and if the move constructor too is deleted, compilation fails. 如果删除了移动构造函数,则编译失败。 Now, the choice must be made between mutable and const: If mutable, then you'll need mutable rvalue reference; 现在,必须在mutable和const之间做出选择:如果是可变的,那么你需要可变的右值引用; otherwise, const lvalue reference. 否则,const左值参考。

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

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