【发布时间】:2010-12-26 07:01:20
【问题描述】:
C++中指向引用的指针、指向指针的引用和指向指针的指针有什么区别?
哪一个应该比另一个更受欢迎?
【问题讨论】:
标签: c++ memory pointers reference
C++中指向引用的指针、指向指针的引用和指向指针的指针有什么区别?
哪一个应该比另一个更受欢迎?
【问题讨论】:
标签: c++ memory pointers reference
首先,对指针的引用就像对任何其他变量的引用:
void fun(int*& ref_to_ptr)
{
ref_to_ptr = 0; // set the "passed" pointer to 0
// if the pointer is not passed by ref,
// then only the copy(parameter) you received is set to 0,
// but the original pointer(outside the function) is not affected.
}
指向引用的指针在 C++ 中是非法的,因为 - 与指针不同 - 引用只是一个概念,它允许程序员为其他东西制作 别名。指针是内存中的位置,它具有其他东西的地址,但引用不是。
如果您坚持将引用作为指针处理,那么最后一点可能还不是很清楚。例如:
int x;
int& rx = x; // from now on, rx is just like x.
// Unlike pointers, refs are not real objects in memory.
int* p = &x; // Ok
int* pr = ℞ // OK! but remember that rx is just x!
// i.e. rx is not something that exists alone, it has to refer to something else.
if( p == pr ) // true!
{ ... }
从上面的代码可以看出,当我们使用引用时,我们并不是在处理与它所引用的东西分开的东西。所以,引用的地址就是它所引用的地址。这就是为什么在你所说的方面没有所谓的参考地址。
【讨论】:
x) 的引用 (rx) 来获取指向该对象的指针。它不是指向引用的指针。
C++ 中的指针只是一个存储内存位置的值(通常为 32 位值)。
假设您有一个用户输入的整数值(78 == 0x4E 十六进制)。
它将以与此类似的方式存储在内存中(我特意为这个示例简化了一些事情):
Memory address Value
0x12345678 0x0000004E
如果你想创建一个指向这个值的“指针”,它在内存中应该是这样的:
Memory address Value
0x22334455 0x12345678
在内存地址0x22334455,您现在有一个“指针”,其值为0x12345678,或存储用户输入整数值(0x4E)的内存地址。
假设您想创建一个指向该指针值的“指针”。它看起来像这样:
Memory address Value
0x11335577 0x22334455
您现在在内存中有一个新的“指针”值,它存储了先前定义的指针值的内存地址。
指针可以像这样无限地创建——关键是要记住指针只是编译器解释为内存位置的另一个值(它提供了各种访问语义,例如 * 和 -> “指针”类型)。
引用可以被认为是另一个真实对象的视图或别名。当您创建对名为 myReference 的指针的引用时,您只是定义了一个名为 myReference 的新名称,可用于访问您之前在内存中定义的指针。
在内部,引用是使用指针实现的,但这超出了您的问题范围。
引用对 C++ 中的其他类型有限制 - 例如,您必须在创建时始终初始化引用以“引用”到真实对象,而指针可能 em> 指向无效或未初始化的内存。
这不存在。如前所述,引用只是另一个对象的别名。您不能“指向”一个引用,因为它本身不是一个对象,而只是一个真实对象的另一个名称。
当然,您可以拥有一个指向引用所指对象的指针。但现在我们又回到了原版指针领域。
当您将参数按值传递给方法或例程时,您实际上是将对象的“副本”传递给方法。当例程返回时,您对例程中的值所做的任何更改都将丢失,因为该参数将被视为例程上下文中的局部变量。
如果要修改传入的参数以便客户端(调用)代码可以访问更改,则必须通过 pointer 或 reference 传递参数.
例如:
void myMethod(int myValue)
{
// NOTE: This change will be lost to the caller!
myValue = 5;
}
void myMethod2(int* myValue)
{
// Correct way of modifying pointer parameter value
*myValue = 5;
}
void myMethod3(int& myValue)
{
// Correct way of modifying reference parameter value
myValue = 5;
}
现在假设您的方法要为指针分配内存。你可能会想这样做:
void myMethod4(int* myValue)
{
// Warning: You will lose the address of the allocated
// memory when you return!
myValue = new int[5];
}
但是请记住,您在这里修改的是指针值的副本,而不是真实的 指针值。由于您要修改此例程中的 pointer,而不是指针“指向”的 value,因此您需要将其作为“指向指针”或“对指针的引用”:
void myMethod5(int** myValue)
{
// Correct way of allocating memory in a method
// via pointer-to-pointer
*myValue = new int[5];
}
void myMethod6(int*& myValue)
{
// Correct way of allocating memory in a method
// via reference-to-pointer
myValue = new int[5];
}
在下面这两个例子中,调用myMethod5 和myMethod6 的代码将通过myValue 参数指针或引用正确获取新分配内存的内存地址。
【讨论】:
没有指向引用的指针。
【讨论】:
引用是对指针的抽象。参考文献比较难搞砸,尤其是对新手来说,而且层次更高。
您不需要 参考资料。您始终可以使用指针。但是,有时使用它们可以更容易地阅读代码。
一个典型的初学者例子是链表。想象一下,您有一个名为“list”的变量,其中包含指向第一个变量的指针。如果你想在头部添加一些东西,你需要给你的 add() 一个双指针,因为它需要能够修改“头部”。但是,您可以改用对指针的引用。在这里,我们想在列表本身中使用指针,因为我们将改变它们,但是如果我们传入对列表头部的引用而不是双指针,那么 add() 函数会更清晰。
它们只是一种风格选择。如果你正在处理一个更大的项目,你应该遵循项目的风格。如果没有,您可以使用任何您认为更可取的东西。但是,如果您甚至希望成为一个稍微成功的 C++ 程序员,那么您应该习惯于使用所有样式。
你不能有一个指向引用的指针也是值得的。这是因为引用实际上只是另一个变量的另一个名称,它可能在其他范围内。拥有一个指向引用的指针是没有意义的。您真正想要的只是指向原始数据的指针,不涉及任何引用。
【讨论】:
请务必注意,虽然引用不是对象,因此没有可访问的地址,但引用可以包含在对象中,并且包含的对象确实有地址。
struct contains_ref
{
int& ref;
contains_ref(int& target) : ref(target) {}
};
“引用是别名”的解释并非不正确,但往往伴随着误导性声明。引用不等同于原始对象。它有自己的生命周期,由包含它的范围或对象决定,而不是它所引用的对象。并且一个引用可以比一个对象更长寿,并且可以用来引用一个在同一地址创建的新对象。
将引用视为真正的引用——围绕指针的抽象,将 null 排除为有效值,并防止重新安装1——而不是什么神奇的东西。引用的唯一非从其指针性质派生的不寻常属性是临时对象的生命周期延长。
1实际上,这是因为 C++ 没有提供任何语法来引用引用本身而不是其目标。所有的运算符,包括赋值运算符,都简单地应用于目标。
【讨论】:
试着亲自看看每个东西都有什么。示例程序只是打印一个 int 的值和不同实体的地址:
#include<stdio.h>
int main(){
int myInt ;
int *ptr_to_myInt = &myInt;
int *ptr_to_myInt_ref = ptr_to_myInt;
myInt = 42;
printf("myInt is %d\n",myInt);
printf("ptr_to_myInt is %x\n",ptr_to_myInt);
printf("ptr_to_myInt_ref is %x\n",ptr_to_myInt_ref);
printf("&ptr_to_myInt is %x\n",&ptr_to_myInt);
return 0;
}
输出:
myInt is 42
ptr_to_myInt is bffff858
ptr_to_myInt_ref is bffff858
&ptr_to_myInt is bffff854
所以,指向 int 的指针和指向 int 引用的指针是完全一样的。从代码中可以看出这一点,因为指向引用的指针只是对指针进行别名的另一种方式(它是说“为我保留以下地址”)。
现在,指针在内存中也需要一些空间,如果您打印对该指针的引用(最后一个 printf 语句),它只是指示指针所在的内存位置。
【讨论】:
c++ 而不是c! references 也是与内存地址不同的主题,它被添加到c++。它们在某种程度上是相关的,但它们并不相同。