我知道引用是语法糖,因此代码更容易读写。
但有什么区别?
以下答案和链接摘要:
NULL
),而引用总是指向一个对象。 &obj + 5
)。 澄清一个误解:
C ++ 标准非常谨慎,以避免规定编译器如何实现引用,但每个 C ++ 编译器都将引用实现为指针。也就是说,声明如下:
int &ri = i;
如果它没有完全优化 ,则分配与指针相同的存储量,并将
i
的地址放入该存储器中。
因此,指针和引用都使用相同数量的内存。
作为基本规则,
有趣的读物:
可以重新分配指针:
int x = 5;
int y = 6;
int *p;
p = &x;
p = &y;
*p = 10;
assert(x == 5);
assert(y == 10);
引用不能,必须在初始化时分配:
int x = 5;
int y = 6;
int &r = x;
指针在堆栈上有自己的内存地址和大小(x86 上为 4 个字节),而引用共享相同的内存地址(使用原始变量),但也会占用堆栈上的一些空间。由于引用与原始变量本身具有相同的地址,因此可以将引用视为同一变量的另一个名称。注意:指针指向的内容可以在堆栈或堆上。同上一个参考。我在这个陈述中的主张并不是指针必须指向堆栈。指针只是一个保存内存地址的变量。此变量位于堆栈上。由于引用在堆栈上有自己的空间,并且因为地址与它引用的变量相同。更多关于堆栈与堆 。这意味着编译器不会告诉您存在引用的真实地址。
int x = 0;
int &r = x;
int *p = &x;
int *p2 = &r;
assert(p == p2);
您可以指向指向提供额外间接级别的指针的指针。而引用仅提供一个间接层。
int x = 0;
int y = 0;
int *p = &x;
int *q = &y;
int **pp = &p;
pp = &q;//*pp = q
**pp = 4;
assert(y == 4);
assert(x == 0);
指针可以直接指定为nullptr
,而引用则不能。如果你足够努力,并且知道如何,你可以创建一个引用nullptr
的地址。同样,如果你足够努力,你可以引用一个指针,然后该引用可以包含nullptr
。
int *p = nullptr;
int &r = nullptr; <--- compiling error
int &r = *p; <--- likely no compiling error, especially if the nullptr is hidden behind a function call, yet it refers to a non-existent int at address 0
指针可以遍历数组,您可以使用++
转到指针指向的下一个项目, + 4
转到第 5 个元素。无论指针指向的对象是什么大小。
需要使用*
取消引用指针以访问它指向的内存位置,而可以直接使用引用。指向类 / 结构的指针使用->
来访问它的成员,而引用使用 a .
。
指针是保存内存地址的变量。无论引用如何实现,引用都具有与其引用的项相同的内存地址。
引用不能填充到数组中,而指针可以是(由用户 @litb 提及)
Const 引用可以绑定到临时值。指针不能(不是没有一些间接):
const int &x = int(12); //legal C++
int *y = &int(12); //illegal to dereference a temporary.
这使得const&
更安全的用于参数列表等等。
引用可以被认为是一个常量指针 (不要与指向常量值的指针混淆!)和自动间接,即编译器将为您应用*
运算符。
必须使用非 null 值初始化所有引用,否则编译将失败。获取引用的地址既不可能 - 地址运算符将返回引用值的地址 - 也不可能在引用上进行算术运算。
C 程序员可能不喜欢 C ++ 引用,因为当间接发生时,或者如果参数通过值或指针传递而不查看函数签名,它将不再是显而易见的。
C ++ 程序员可能不喜欢使用指针,因为它们被认为是不安全的 - 虽然引用并不比常量指针更安全,除了在最微不足道的情况下 - 缺乏自动间接的便利性并带有不同的语义内涵。
请考虑C ++ FAQ 中的以下语句:
即使参考使用底层汇编语言的地址经常被实现,请不要以为引用作为好笑的看着指针指向的对象。参考是对象。它不是指向对象的指针,也不是对象的副本。这是对象。
但如果参考确实是对象,那么怎么会有悬空引用呢?在非托管语言中,引用不可能比指针更 “安全” - 通常只是不能跨范围边界可靠地对值进行别名!
来自 C 背景,C ++ 引用可能看起来像一个有点愚蠢的概念,但是在可能的情况下仍然应该使用它们而不是指针:自动间接是方便的,并且在处理RAII时引用变得特别有用 - 但不是因为任何感知的安全性优点,而是因为它们使写作惯用代码不那么尴尬。
RAII 是 C ++ 的核心概念之一,但它与复制语义非常简单地交互。通过引用传递对象避免了这些问题,因为不涉及复制。如果语言中没有引用,则必须使用指针,这些指针使用起来比较麻烦,因此违反了语言设计原则,即最佳实践解决方案应该比替代方案更容易。
如果你想变得非常迂腐,你可以用引号做一件事,你不能用指针做:延长临时对象的生命周期。在 C ++ 中,如果将 const 引用绑定到临时对象,则该对象的生命周期将成为引用的生命周期。
std::string s1 = "123";
std::string s2 = "456";
std::string s3_copy = s1 + s2;
const std::string& s3_reference = s1 + s2;
在此示例中,s3_copy 复制作为串联结果的临时对象。而 s3_reference 本质上成为临时对象。它实际上是对临时对象的引用,该临时对象现在具有与引用相同的生命周期。
如果你在没有const
情况下尝试这个,它将无法编译。您不能将非 const 引用绑定到临时对象,也不能为此处获取其地址。