指针变量和引用变量之间的区别是什么?
当前回答
为了避免混淆,我想输入一些输入,我确信这主要取决于编译器如何实现引用,但在gcc的情况下,引用只能指向堆栈上的变量的想法实际上并不正确,例如:
#include <iostream>
int main(int argc, char** argv) {
// Create a string on the heap
std::string *str_ptr = new std::string("THIS IS A STRING");
// Dereference the string on the heap, and assign it to the reference
std::string &str_ref = *str_ptr;
// Not even a compiler warning! At least with gcc
// Now lets try to print it's value!
std::cout << str_ref << std::endl;
// It works! Now lets print and compare actual memory addresses
std::cout << str_ptr << " : " << &str_ref << std::endl;
// Exactly the same, now remember to free the memory on the heap
delete str_ptr;
}
其输出如下:
THIS IS A STRING
0xbb2070 : 0xbb2070
如果您注意到甚至内存地址都完全相同,这意味着引用成功地指向了堆上的一个变量!现在,如果你真的想变得古怪,这也很有效:
int main(int argc, char** argv) {
// In the actual new declaration let immediately de-reference and assign it to the reference
std::string &str_ref = *(new std::string("THIS IS A STRING"));
// Once again, it works! (at least in gcc)
std::cout << str_ref;
// Once again it prints fine, however we have no pointer to the heap allocation, right? So how do we free the space we just ignorantly created?
delete &str_ref;
/*And, it works, because we are taking the memory address that the reference is
storing, and deleting it, which is all a pointer is doing, just we have to specify
the address with '&' whereas a pointer does that implicitly, this is sort of like
calling delete &(*str_ptr); (which also compiles and runs fine).*/
}
其输出如下:
THIS IS A STRING
因此,引用是引擎盖下的指针,它们都只是存储一个内存地址,地址指向的位置是不相关的,如果我调用std::cout<<str_ref;调用delete str_ref后?很明显,它编译得很好,但在运行时会导致分段错误,因为它不再指向有效变量,我们本质上有一个中断的引用仍然存在(直到它超出范围),但没有用。
换句话说,引用只是一个指针,它抽象了指针机制,使其更安全、更容易使用(没有意外的指针数学,没有混淆“.”和“->”等),假设您没有像上面的例子那样尝试任何废话;)
现在,不管编译器如何处理引用,它总是有某种指针,因为引用必须引用特定内存地址处的特定变量,才能按预期工作,因此无法绕过这一点(因此称为“引用”)。
对于引用,唯一需要记住的重要规则是必须在声明时定义它们(头中的引用除外,在这种情况下,必须在构造函数中定义引用,在构造包含引用的对象之后,再定义它就太晚了)。
请记住,我上面的例子只是说明引用是什么的例子,你永远不想以这些方式使用引用!为了正确使用参考文献,这里已经有很多答案,这些答案一针见血
其他回答
以下答案和链接的摘要:
指针可以被重新分配任意次数,而引用在绑定后不能被重新分配。指针可以指向任何地方(NULL),而引用总是指向对象。不能像使用指针那样获取引用的地址。没有“引用算术”(但您可以获取引用指向的对象的地址,并对其进行指针算术,如&obj+5中所示)。
澄清误解:
C++标准非常小心,避免规定编译器如何实现引用,但每个C++编译器都实现引用作为指针。即,声明如下:int&ri=i;如果没有完全优化,则分配相同数量的存储作为指针,并放置地址把我的东西放进那个储藏室。
因此,指针和引用都使用相同的内存量。
作为一般规则,
使用函数参数和返回类型中的引用来提供有用的自记录接口。使用指针实现算法和数据结构。
有趣的阅读:
我最喜欢的C++常见问题解答。参考与指针。参考文献简介。参考和常量。
不能像指针一样取消引用,当取消引用时,
引用和指针都是通过地址工作的。。。
so
你可以这样做
int*val=0xDEADBEEF;*val是0xDEADBEEF的值。
你不能这样做int&V=1;
*不允许使用val。
这是基于教程。所写内容更清楚:
>>> 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。忘记这种说法的术语也是可以的,即创建一个对汤姆的引用。
除了语法糖,引用是常量指针(而不是指向常量的指针)。在声明引用变量时,必须确定它所指的内容,以后不能更改它。
更新:现在我再考虑一下,有一个重要的区别。
常量指针的目标可以通过获取其地址并使用常量转换来替换。
引用的目标不能以UB以外的任何方式替换。
这应该允许编译器对引用进行更多优化。
如果你真的想变得迂腐,有一件事你可以用指针做,但不能用指针做:延长临时对象的生命周期。在C++中,如果将常量引用绑定到临时对象,则该对象的生存期将变为引用的生存期。
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本质上成为临时对象。它实际上是对临时对象的引用,该对象现在与引用具有相同的生存期。
如果您尝试在没有常量的情况下执行此操作,它将无法编译。不能将非常量引用绑定到临时对象,也不能为此获取其地址。
推荐文章
- 如何构建和使用谷歌TensorFlow c++ api
- 断言是邪恶的吗?
- 下面这些短语在c++中是什么意思:0 -,default-和value-initialization?
- 在STL地图中,使用map::insert比[]更好吗?
- C++ Linux的想法?
- 如何为Fedora安装g++ ?
- Std::cin输入空格?
- c++标准是否要求iostreams的性能很差,或者我只是在处理一个糟糕的实现?
- gcc在哪里查找C和c++头文件?
- 为什么我们需要require require ?
- 解析c++中的命令行参数?
- 我如何在c++中创建一个随机的字母数字字符串?
- c++中的atan和atan2有什么区别?
- 现代c++能让你免费获得性能吗?
- 一门语言是如何自我扩展的?