指针变量和引用变量之间的区别是什么?
当前回答
以下答案和链接的摘要:
指针可以被重新分配任意次数,而引用在绑定后不能被重新分配。指针可以指向任何地方(NULL),而引用总是指向对象。不能像使用指针那样获取引用的地址。没有“引用算术”(但您可以获取引用指向的对象的地址,并对其进行指针算术,如&obj+5中所示)。
澄清误解:
C++标准非常小心,避免规定编译器如何实现引用,但每个C++编译器都实现引用作为指针。即,声明如下:int&ri=i;如果没有完全优化,则分配相同数量的存储作为指针,并放置地址把我的东西放进那个储藏室。
因此,指针和引用都使用相同的内存量。
作为一般规则,
使用函数参数和返回类型中的引用来提供有用的自记录接口。使用指针实现算法和数据结构。
有趣的阅读:
我最喜欢的C++常见问题解答。参考与指针。参考文献简介。参考和常量。
其他回答
这是基于教程。所写内容更清楚:
>>> The address that locates a variable within memory is
what we call a reference to that variable. (5th paragraph at page 63)
>>> The variable that stores the reference to another
variable is what we call a pointer. (3rd paragraph at page 64)
简单地记住,
>>> reference stands for memory location
>>> pointer is a reference container (Maybe because we will use it for
several times, it is better to remember that reference.)
此外,我们可以参考几乎任何指针教程,指针是指针算术支持的对象,它使指针类似于数组。
看看下面的陈述,
int Tom(0);
int & alias_Tom = Tom;
alias_Tom可以理解为变量的别名(与typedef不同,typedef是一种类型的别名)Tom。忘记这种说法的术语也是可以的,即创建一个对汤姆的引用。
除非我需要以下任何一项,否则我会使用参考资料:
空指针可以用作哨兵价值,通常是一种廉价的方式避免函数重载或使用嘘声。你可以在指针上做算术。例如,p+=偏移量;
简单地说,我们可以说引用是变量的替代名称,指针是保存另一个变量地址的变量。例如
int a = 20;
int &r = a;
r = 40; /* now the value of a is changed to 40 */
int b =20;
int *ptr;
ptr = &b; /*assigns address of b to ptr not the value */
引用与指针非常相似,但它们是专门设计的,有助于优化编译器。
引用的设计使得编译器更容易跟踪哪些引用别名哪些变量。两个主要特性非常重要:没有“引用算术”,也没有重新分配引用。这些允许编译器在编译时找出哪些引用别名哪些变量。允许引用没有内存地址的变量,例如编译器选择放入寄存器的变量。如果获取局部变量的地址,编译器很难将其放入寄存器中。
例如:
void maybeModify(int& x); // may modify x in some way
void hurtTheCompilersOptimizer(short size, int array[])
{
// This function is designed to do something particularly troublesome
// for optimizers. It will constantly call maybeModify on array[0] while
// adding array[1] to array[2]..array[size-1]. There's no real reason to
// do this, other than to demonstrate the power of references.
for (int i = 2; i < (int)size; i++) {
maybeModify(array[0]);
array[i] += array[1];
}
}
优化编译器可能会意识到,我们正在访问一个[0]和一个[1]。它希望优化算法以:
void hurtTheCompilersOptimizer(short size, int array[])
{
// Do the same thing as above, but instead of accessing array[1]
// all the time, access it once and store the result in a register,
// which is much faster to do arithmetic with.
register int a0 = a[0];
register int a1 = a[1]; // access a[1] once
for (int i = 2; i < (int)size; i++) {
maybeModify(a0); // Give maybeModify a reference to a register
array[i] += a1; // Use the saved register value over and over
}
a[0] = a0; // Store the modified a[0] back into the array
}
要进行这样的优化,需要证明在调用期间没有任何东西可以改变数组[1]。这很容易做到。i永远不小于2,所以array[i]永远不能引用array[1]。maybeModify()被给定a0作为引用(别名数组[0])。因为没有“引用”算法,编译器只需要证明maybeModify永远不会得到x的地址,并且它已经证明没有任何东西会改变数组[1]。
它还必须证明,当我们在a0中有一个[0]的临时寄存器副本时,将来的调用不可能读/写它。这通常很难证明,因为在许多情况下,引用显然从未存储在类实例这样的永久结构中。
现在用指针做同样的事情
void maybeModify(int* x); // May modify x in some way
void hurtTheCompilersOptimizer(short size, int array[])
{
// Same operation, only now with pointers, making the
// optimization trickier.
for (int i = 2; i < (int)size; i++) {
maybeModify(&(array[0]));
array[i] += array[1];
}
}
行为是相同的;直到现在,要证明maybeModify从未修改过数组[1]要困难得多,因为我们已经给了它一个指针;猫从袋子里出来了。现在它必须做更困难的证明:对maybeModify进行静态分析,以证明它从未写入&x+1。它还必须证明它从未保存过可以引用数组[0]的指针,这同样棘手。
现代编译器在静态分析方面越来越好,但帮助他们并使用引用总是很好的。
当然,除非进行这种巧妙的优化,编译器确实会在需要时将引用转换为指针。
编辑:在发布这个答案五年后,我发现了一个实际的技术差异,即引用不同于看待相同寻址概念的不同方式。引用可以以指针无法修改的方式修改临时对象的寿命。
F createF(int argument);
void extending()
{
const F& ref = createF(5);
std::cout << ref.getArgument() << std::endl;
};
通常,临时对象(例如通过调用createF(5)创建的对象)会在表达式末尾被销毁。然而,通过将该对象绑定到引用ref,C++将延长该临时对象的寿命,直到ref超出范围。
我总是根据C++核心指南中的这条规则来决定:
当“无参数”是有效选项时,优先选择T*而不是T&
推荐文章
- 什么是“参数依赖查找”(又名ADL,或“Koenig查找”)?
- 公共朋友交换成员函数
- 如何在Go中使用c++
- 自定义c++分配器的引人注目的例子?
- RAII和c++中的智能指针
- 如何构建和使用谷歌TensorFlow c++ api
- 断言是邪恶的吗?
- 下面这些短语在c++中是什么意思:0 -,default-和value-initialization?
- 在STL地图中,使用map::insert比[]更好吗?
- C++ Linux的想法?
- 如何为Fedora安装g++ ?
- Std::cin输入空格?
- c++标准是否要求iostreams的性能很差,或者我只是在处理一个糟糕的实现?
- gcc在哪里查找C和c++头文件?
- 为什么我们需要require require ?