为什么要使用参考而不是原始参考?

Why would you use a reference rather than the original?

本文关键字:参考 原始 为什么      更新时间:2023-10-16

这个问题可能看起来很主观,但实际上,我正在寻找一个客观原因,比如技术和逻辑部分。 因此,让我们为变量 x 声明一个别名:

int x = 333;
int &xx = x;

为什么不直接使用 x 并省去创建别名/引用的麻烦呢?

除了gsamaras所说的引用之外,当你想修改某些东西时可以使用

参考
std::vector<int> myvector{ 1,2,3,4,5 };
for (auto& elem : myvector) ++elem;

我们不要声明它。在这种情况下,您只需与x一起使用即可。

但是,当您处理大型对象(例如大型类,甚至是泰坦尼克号向量)时,您不想复制整个内容,这就是为什么您将引用传递给需要该类/对象/任何内容的函数的原因。

通过引用而不是按值将对象作为函数参数传递或返回

可能是最重要的原因。有关更多信息,请阅读为什么要使用引用变量?

除了其他答案中描述的函数调用和循环用法外,我还喜欢使用引用来避免重复取消引用深度嵌套结构。

所以不是写

collection.container[i].subcontainer->item.func_a();
collection.container[i].subcontainer->item.func_b();
collection.container[i].subcontainer->item.data = d;

我有时使用

auto & cur_item = collection.container[i].subcontainer->item;
cur_item.func_a();
cur_item.func_b();
cur_item.data = d;

您正在寻找在块范围内使用引用而不是对象的充分理由?

引用绑定到对象,并允许使用替代方法来标识它们。在您的示例中保存 333 的变量本质上只有两个名称。如果查看生成的程序集,则可能甚至看不到除对象之外的任何内容的分配。 例如,此代码:

#include <iostream>
#include <cstdlib>
#include <ctime>
int main()
{
std::srand(std::time(NULL));
int x = std::rand();
int &xx = x;
++xx;
std::cout << xx;
return 0;
}

启用优化时生成此程序集:

main:
sub     rsp, 8
mov     edi, 0
call    time
mov     edi, eax
call    srand
call    rand
lea     esi, [rax+1]
mov     edi, OFFSET FLAT:std::cout
call    std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov     eax, 0
add     rsp, 8
ret
_GLOBAL__sub_I_main:
sub     rsp, 8
mov     edi, OFFSET FLAT:std::__ioinit
call    std::ios_base::Init::Init()
mov     edx, OFFSET FLAT:__dso_handle
mov     esi, OFFSET FLAT:std::__ioinit
mov     edi, OFFSET FLAT:std::ios_base::Init::~Init()
call    __cxa_atexit
add     rsp, 8
ret

如果您在实时示例中检查这一点并查看哪些代码映射到何处,您会注意到绝对没有剩余的引用表示形式。所有访问都是对对象的访问。

因此,如果块范围内的引用只是为对象提供另一个名称的一种奇特方式,那么它就不是那么有用了。但是,如果对象一开始没有名称怎么办?

例如:

std::string foo() { return "Hello World!"; }
int main() {
foo();
}

当我调用foo时,它会返回一个存储结果的临时对象。该对象是无名的。我可以直接使用它,也可以在通话后达到;的纳秒内消失。当然,我可以复制它:

std::string res = foo();

但是,如果字符串很长,而我只想打印几次怎么办。为什么我必须浪费时间在副本上?

事实证明,您不必复制:

std::string const &res = foo();

以上不是悬而未决的参考!常量引用可以绑定到临时对象。C++语言承诺,只要引用在该块范围内存在,该对象就会存在。本质上,我们可以命名对象并在调用后使其可用,从而保存副本。