指针变量和引用变量之间有什么区别?
什么是C++引用(针对C程序员)
可以将引用视为自动间接的常量指针(不要与指向常量值的指针混淆!)。也就是说,编译器将为您应用*
运算符。
所有引用必须使用非空值进行初始化,否则编译将失败。无法获取引用的地址 - 地址运算符将返回所引用值的地址 - 也无法在引用上进行算术运算。
C程序员可能不喜欢C++引用,因为不再明显地看出间接引用发生的位置或是否按值或指针传递参数,需要查看函数签名才能确定。
C++程序员可能不喜欢使用指针,因为它们被认为是不安全的,尽管除了最简单的情况之外,引用与常量指针并没有真正的安全性差异,缺乏自动间接的方便性,并具有不同的语义含义。
考虑下面的语句来自C++ FAQ:
尽管引用通常是使用底层汇编语言中的地址实现的,请不要认为引用是一个指向对象的奇怪指针。引用就是对象。它不是对象的指针,也不是对象的副本。它就是对象本身。
但是,如果引用确实是对象,那么怎么会有悬挂引用呢?在非托管语言中,引用通常比指针不会更安全 - 通常没有一种可靠地在范围边界之间别名值的方法!
为什么我认为C++引用很有用
从C背景出发,C++引用可能看起来有些愚蠢的概念,但应该尽可能使用它们而不是指针:自动间接引用很方便,而且引用在处理RAII时特别有用 - 但不是因为任何感知的安全优势,而是因为它们使编写惯用代码更不尴尬。
RAII 是 C++ 的核心概念之一,但它与复制语义交互起来并不容易。通过引用传递对象避免了这些问题,因为不涉及复制。如果语言中没有引用,你将不得不使用指针,这样使用起来更加麻烦,违反了语言设计原则,即最佳实践解决方案应该比替代方案更容易。
-
指针可以被重新赋值:
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 &q; // error int &r = x;
-
指针变量具有自己的身份:一个不同的、可见的内存地址,可以用一元运算符
&
获取,并且可以用sizeof
运算符测量一定量的空间。在引用上使用这些运算符返回与引用绑定的值;引用自己的地址和大小是不可见的。由于引用以这种方式假定了原始变量的身份,因此可以方便地将引用视为相同变量的另一个名称。int x = 0; int &r = x; int *p = &x; int *p2 = &r; assert(p == p2); // &x == &r assert(&p != &p2);
-
您可以拥有任意嵌套的指向指针的指针,提供额外级别的间接引用。引用仅提供一级间接引用。
int x = 0; int y = 0; int *p = &x; int *q = &y; int **pp = &p; **pp = 2; pp = &q; // *pp is now q **pp = 4; assert(y == 4); assert(x == 2);
-
指针可以被赋值为
nullptr
,而引用必须绑定到现有对象。如果您努力尝试,可以将引用绑定到nullptr
,但这是未定义的,并且不会表现一致。/* the code below is undefined; your compiler may optimise it * differently, emit warnings, or outright refuse to compile it */ int &r = *static_cast
(nullptr); // prints "null" under GCC 10 std::cout << (&r != nullptr ? "not null" : "null") << std::endl; bool f(int &r) { return &r != nullptr; } // prints "not null" under GCC 10 std::cout << (f(*static_cast (nullptr)) ? "not null" : "null") << std::endl; 但是,您可以拥有指向值为
nullptr
的指针的引用。 -
指针可以迭代数组;您可以使用
++
转到指针指向的下一个项目,使用+ 4
转到第5个元素。这不管指针指向的对象的大小如何。 -
需要使用
*
对指针进行间接引用以访问其指向的内存位置,而引用可以直接使用。指向类/结构体的指针使用->
访问其成员,而引用使用.
。 -
不能将引用放入数组中,而指针可以(由用户@litb提到)
-
const引用可以绑定到临时对象。指针不能(不带某些间接方式):
const int &x = int(12); // legal C++ int *y = &int(12); // illegal to take the address of a temporary.
这使得在参数列表等中使用
const &
更方便。