从c++方法返回引用和副本

Returning a reference vs. a copy from a C++ method

本文关键字:副本 引用 返回 c++ 方法      更新时间:2023-10-16

我目前正在学习c++,我对从方法返回引用的概念有点困惑。考虑下面的玩具示例:

#include <iostream>
#include <vector>
class IntHolder {
private:
    std::vector<int> d_values;
public:
    IntHolder() {
        d_values.push_back(1);
        d_values.push_back(2);
        d_values.push_back(3);
    }
    std::vector<int> &values() {
        return d_values;
    }
};
int main(int argc, char **argv) {
    IntHolder h;
    std::vector<int> ret_val = h.values();
    std::cout << ret_val.size() << std::endl;
    ret_val.push_back(4);
    ret_val.push_back(5);
    std::cout << h.values().size() << std::endl;
    return 0;
}

将以下内容打印到标准输出:

3
3

既然我们返回的是对d_values的引用,那么返回的对象不应该与存储在IntHolder实例中的对象相同吗?因此,当再次调用h.values()时,我们应该看到大小为5?

既然不是这样,那么返回对象的引用和对象的副本有什么区别呢?当你从一个方法返回时有什么不同吗?

values函数返回引用,但您没有返回的对象分配给引用变量。相反,您正在对它进行复制,因为您将其分配给名为ret_val的新std::vector<int>

您希望像这样修改代码,以便捕获返回的引用:

std::vector<int>& ret_val = h.values();

或者简单地:

auto& ret_val = h.values();

您的方法返回一个引用,但是您随后将结果赋值给另一个向量,从而导致复制。要解决这个问题,将ret_val定义更改为:

std::vector<int> & ret_val = h.values();

如果返回引用,则返回相同的对象,而不是创建副本。从根本上看,它似乎正如你所期望的那样:

std::cout << h.values().size() << std::endl;
h.values().push_back(4);
h.values().push_back(5);
std::cout << h.values().size() << std::endl;

回来
3
5

是另一个错误。让我们看看

std::vector<int> ret_val = h.values();

您发现ret_valh.d_values的副本,而h.values()返回对它的引用。我们可以将上面的代码重写如下:

std::vector<int> &ret_ref = h.values(); // object returned by `h.values()`
std::vector<int>  ret_val = ret_ref;

如果你调用ret_ref.push_back(4), h.d_values将改变。但是ret_val是返回对象的副本,不会影响h.d_values