指向引用的指针和指向指针的引用之间的区别

时间:2021-02-12 13:30:06

What is the difference between pointer to a reference, reference to a pointer and pointer to a pointer in C++?

在c++中,指向引用的指针、指向指针的指针和指向指针的指针之间的区别是什么?

Where should one be preferred over the other?

哪里应该优先考虑另一方?

6 个解决方案

#1


49  

First, a reference to a pointer is like a reference to any other variable:

首先,对指针的引用就像对其他变量的引用:

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.
}

A pointer to reference is illegal in C++, because -unlike a pointer- a reference is just a concept that allows the programmer to make aliases of something else. A pointer is a place in memory that has the address of something else, but a reference is NOT.

在c++中,指向引用的指针是非法的,因为与指针不同,引用只是一个概念,允许程序员对其他东西进行别名。指针是内存中有其他地址的地方,但引用不是。

Now the last point might not be crystal clear, if you insist on dealing with references as pointers. e.g.:

现在,如果您坚持将引用作为指针来处理,那么最后一点可能不太清楚。例如:

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!
{ ... }

As you can see from the above code, when we use the reference, we are not dealing with something separated from what it refers to. So, the address of a reference is just the address of what it refers to. Thats why there is no such thing called the address of the reference in terms of what you are talking about.

正如您从上面的代码中可以看到的,当我们使用引用时,我们并不是在处理与引用相分离的东西。引用的地址就是引用的地址。这就是为什么在你谈论的内容中没有所谓的引用地址。

#2


40  

Pointer to a pointer

A pointer in C++ is just a value which stores a memory location (generally as a 32-bit value).

c++中的指针仅是存储内存位置(通常是32位值)的值。

Let's say you had an user input integer value (78 == 0x4E in hex).

假设您有一个用户输入的整数值(78 = 0x4E在十六进制中)。

It would be stored in memory in a similar way to this (I'm purposely simplifying things for this example):

它将以类似的方式存储在内存中(我特意为这个示例简化了一些内容):

Memory address    Value
0x12345678        0x0000004E

If you wanted to create a "pointer" to this value, it would look like this in memory:

如果您想要创建这个值的“指针”,那么在内存中应该是这样的:

Memory address    Value
0x22334455        0x12345678

At memory address 0x22334455 you now have a "pointer" whose value is 0x12345678, or the memory address of where the user input integer value (0x4E) is stored.

在内存地址0x22334455处,您现在有一个值为0x12345678的“指针”,或者存储用户输入整数值(0x4E)的内存地址。

Let's say you wanted to create a "pointer" to this pointer value. It would look like this:

假设您想要创建一个指向该指针值的“指针”。它看起来是这样的:

Memory address    Value
0x11335577        0x22334455

You now have a new "pointer" value in memory which is storing the memory address of the previously-defined pointer value.

现在,在内存中有一个新的“指针”值,该值存储先前定义的指针值的内存地址。

Pointers can be created like this indefinitely - the key is remembering that a pointer is just another value that the compiler interprets as a memory location (and it provides various access semantics such as * and -> which are special to "pointer" types).

指针可以无限地创建——关键是要记住一个指针只是编译器将其作为一个内存位置来解释的另一个值(它提供了各种访问语义,如*和->,它们对“指针”类型是特殊的)。

Reference to a pointer

A reference can be thought of as a view, or alias, on to another real object. When you create a reference to a pointer called myReference, you are simply defining a new name called myReference which can be used to access the pointer which you have previous defined in memory.

引用可以被认为是另一个真实对象上的视图或别名。当您为一个名为myReference的指针创建引用时,您只需定义一个名为myReference的新名称,该名称可用于访问您之前在内存中定义的指针。

Internally, references are implemented using pointers, but this is beyond the scope of your question.

在内部,引用是使用指针实现的,但这超出了您的问题范围。

References have restrictions over other types in C++ - for example, you must always initialize a reference to "refer" to a real object when you create it, while a pointer may point to memory which is invalid, or uninitialised.

引用对c++中的其他类型有限制——例如,在创建一个实际对象时,必须初始化一个引用来“引用”它,而指针可能指向无效或未初始化的内存。

Pointer to a reference

This doesn't exist. As stated earlier, a reference is merely an alias to another object. You can't "point" to a reference, because it isn't an object in itself but merely another name for a real object.

这并不存在。如前所述,引用只是另一个对象的别名。你不能“指向”一个引用,因为它本身不是一个对象,而是一个真实对象的另一个名称。

Of course, you can have a pointer to the object that a reference is referring to. But now we are back in vanilla pointer territory.

当然,可以有指向引用所指对象的指针。但现在我们又回到了香草指针领域。

Note about parameters

When you pass a parameter by value to a method or routine, you are essentially passing a "copy" of the object to the method. Any changes you make to the value within the routine will be lost when the routine returns, because the parameter will be treated as a local variable in the context of the routine.

当您将参数按值传递给方法或例程时,实际上是将对象的“拷贝”传递给方法。当例程返回时,您对例程中的值所做的任何更改都将丢失,因为参数将在例程的上下文中作为局部变量处理。

If you want to modify a parameter which is passed in so the client (calling) code can access the change, you must pass the parameter by pointer or by reference.

如果要修改传入的参数,因此客户端(调用)代码可以访问更改,则必须通过指针或引用传递参数。

For example:

例如:

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;
}

Let's now say that your method wants to allocate memory for a pointer. You could be tempted to do this:

现在我们说,您的方法希望为指针分配内存。你可能会这么做:

void myMethod4(int* myValue)
{
    // Warning: You will lose the address of the allocated
    // memory when you return!
    myValue = new int[5];
}

But remember, you are modifying the copy of the pointer value here, not the real pointer value. Since you are wanting to modify the pointer in this routine, and not the value that the pointer "points" to, you need to pass it in as a "pointer to a pointer" or a "reference to a pointer":

但是请记住,您正在修改指针值的副本,而不是真正的指针值。由于您希望修改这个例程中的指针,而不是指针指向的值,所以需要将其作为“指向指针的指针”或“指向指针的引用”传递进去:

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];
}

In these bottom 2 examples, the code which is calling myMethod5 and myMethod6 will correctly get the memory address of the newly-allocated memory via the myValue parameter pointer or reference.

在下面两个示例中,调用myMethod5和myMethod6的代码将通过myValue参数指针或引用正确地获取新分配内存的地址。

#3


9  

There is no such thing as a pointer to a reference.

没有指向引用的指针。

#4


5  

A reference is an abstraction away from pointers. References are a bit harder to screw up, especially for novices, and are a bit more high level.

引用是一种脱离指针的抽象。参考文献有点难搞砸,尤其是对新手来说,而且要高一些。

You don't need references. You can always use pointers. However, sometimes code can be easier to read with them.

你不需要引用。你可以一直使用指针。然而,有时代码可以更容易与它们一起阅读。

A typical beginner example is a linked list. Imagine you have a variable called "list" that contains a pointer to the first one. If you wanted to add something to the head, you'd need to give your add() a double pointer, since it needs to be able to modify "head". However, you can use a reference to a pointer instead. Here, we want to use pointers in the list itself since we'll be mutating them, but the add() function will be clearer if we pass in a reference to the head of the list instead of a double pointer.

一个典型的初学者例子是链表。假设您有一个名为“list”的变量,其中包含指向第一个的指针。如果您想向head添加一些东西,您需要给add()一个双指针,因为它需要能够修改“head”。但是,您可以使用指针的引用。在这里,我们希望在列表本身中使用指针,因为我们将对它们进行修改,但是如果我们将引用传递给列表的头部而不是双指针,那么add()函数将更清晰。

They're simply a style choice. If you're working on a larger project, you should go with the style of the project. If not, you can use whatever you feel is preferable. You should, however, be comfortable using all styles if you even hope to be a mildly successful C++ programmer.

它们只是一种风格的选择。如果你在做一个更大的项目,你应该遵循项目的风格。如果没有,你可以用你认为更好的。但是,如果您甚至希望成为一个稍微成功的c++程序员,那么您应该对使用所有样式感到放心。

It is also worthwhile that you can't have a pointer to a reference. This is because references are really just another name for another variable, which may be in some other scope. Having a pointer to a reference doesn't make sense. What you'd really want is just a pointer to whatever the original data was, no references involved.

同样值得注意的是,您不能有指向引用的指针。这是因为引用实际上只是另一个变量的名称,它可能在其他的范围内。有指向引用的指针是没有意义的。你真正想要的只是一个指向原始数据的指针,不涉及任何引用。

#5


4  

It is important to note that although a reference is not an object and therefore does not have an accessible address, a reference can be contained within an object and the containing object does have an address.

需要注意的是,虽然引用不是对象,因此没有可访问的地址,但是引用可以包含在对象中,并且包含的对象确实有地址。

struct contains_ref
{
     int& ref;
     contains_ref(int& target) : ref(target) {}
};

The "reference is an alias" explanation is not incorrect, but is often accompanied by misleading claims. A reference is not equivalent to the original object. It has its own lifetime, determined by the scope or object that contains it, and not the object it refers to. And a reference can outlive an object and be used to refer to a new object created at the same address.

“引用是别名”的解释并非不正确,但往往伴随着误导性的声明。引用并不等同于原始对象。它有自己的生命周期,由包含它的范围或对象决定,而不是它引用的对象。一个引用可以比一个对象活得长,并且可以用来引用在同一个地址创建的新对象。

Treat a reference as what it really is -- an abstraction around a pointer that excludes null as a valid value, and prevents reseating1 -- and not something magic. The only unusual property of a reference that isn't derived from its pointer nature is lifetime extension of temporaries.

把引用当作它真正的样子——一个围绕指针的抽象,它将null排除为一个有效值,并防止reseating1——而不是什么神奇的东西。引用的唯一不同寻常的属性不是从它的指针属性派生出来的,它是临时变量的生命周期扩展。


1Actually this is a consequence of the fact that C++ doesn't provide any syntax for referring to the reference itself rather than its target. All operators, including the assignment operator, are simply applied to the target.

实际上,这是由于c++没有提供任何语法来引用引用本身而不是它的目标。所有操作符(包括赋值操作符)都只应用于目标。

#6


0  

Just try and see for yourself what is each thing holding. The sample program simply prints the value for an int and the addresses of different entities:

试着自己看看每件东西都装了些什么。示例程序仅打印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;
}

Output:

输出:

myInt is 42
ptr_to_myInt is bffff858
ptr_to_myInt_ref is bffff858
&ptr_to_myInt is bffff854

So, the pointer to the int and the pointer to the reference of the int are exactly the same thing. This is obvious from the code, because the pointer to a reference is simply another way of aliasing a pointer (it is saying "hold the following address for me").

所以指向int的指针和指向int引用的指针是完全相同的。从代码中可以明显看出这一点,因为指向引用的指针仅仅是另一种别名指针(它的意思是“为我保留以下地址”)。

Now, the pointer also needs some space in memory, and if you print the reference to this pointer (the last printf statement) it simply indicates the place in memory where the pointer resides.

现在,指针还需要内存中的一些空间,如果您将引用打印到这个指针(最后的printf语句),它只会指示指针所在的内存中的位置。

#1


49  

First, a reference to a pointer is like a reference to any other variable:

首先,对指针的引用就像对其他变量的引用:

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.
}

A pointer to reference is illegal in C++, because -unlike a pointer- a reference is just a concept that allows the programmer to make aliases of something else. A pointer is a place in memory that has the address of something else, but a reference is NOT.

在c++中,指向引用的指针是非法的,因为与指针不同,引用只是一个概念,允许程序员对其他东西进行别名。指针是内存中有其他地址的地方,但引用不是。

Now the last point might not be crystal clear, if you insist on dealing with references as pointers. e.g.:

现在,如果您坚持将引用作为指针来处理,那么最后一点可能不太清楚。例如:

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 = &rx; // 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!
{ ... }

As you can see from the above code, when we use the reference, we are not dealing with something separated from what it refers to. So, the address of a reference is just the address of what it refers to. Thats why there is no such thing called the address of the reference in terms of what you are talking about.

正如您从上面的代码中可以看到的,当我们使用引用时,我们并不是在处理与引用相分离的东西。引用的地址就是引用的地址。这就是为什么在你谈论的内容中没有所谓的引用地址。

#2


40  

Pointer to a pointer

A pointer in C++ is just a value which stores a memory location (generally as a 32-bit value).

c++中的指针仅是存储内存位置(通常是32位值)的值。

Let's say you had an user input integer value (78 == 0x4E in hex).

假设您有一个用户输入的整数值(78 = 0x4E在十六进制中)。

It would be stored in memory in a similar way to this (I'm purposely simplifying things for this example):

它将以类似的方式存储在内存中(我特意为这个示例简化了一些内容):

Memory address    Value
0x12345678        0x0000004E

If you wanted to create a "pointer" to this value, it would look like this in memory:

如果您想要创建这个值的“指针”,那么在内存中应该是这样的:

Memory address    Value
0x22334455        0x12345678

At memory address 0x22334455 you now have a "pointer" whose value is 0x12345678, or the memory address of where the user input integer value (0x4E) is stored.

在内存地址0x22334455处,您现在有一个值为0x12345678的“指针”,或者存储用户输入整数值(0x4E)的内存地址。

Let's say you wanted to create a "pointer" to this pointer value. It would look like this:

假设您想要创建一个指向该指针值的“指针”。它看起来是这样的:

Memory address    Value
0x11335577        0x22334455

You now have a new "pointer" value in memory which is storing the memory address of the previously-defined pointer value.

现在,在内存中有一个新的“指针”值,该值存储先前定义的指针值的内存地址。

Pointers can be created like this indefinitely - the key is remembering that a pointer is just another value that the compiler interprets as a memory location (and it provides various access semantics such as * and -> which are special to "pointer" types).

指针可以无限地创建——关键是要记住一个指针只是编译器将其作为一个内存位置来解释的另一个值(它提供了各种访问语义,如*和->,它们对“指针”类型是特殊的)。

Reference to a pointer

A reference can be thought of as a view, or alias, on to another real object. When you create a reference to a pointer called myReference, you are simply defining a new name called myReference which can be used to access the pointer which you have previous defined in memory.

引用可以被认为是另一个真实对象上的视图或别名。当您为一个名为myReference的指针创建引用时,您只需定义一个名为myReference的新名称,该名称可用于访问您之前在内存中定义的指针。

Internally, references are implemented using pointers, but this is beyond the scope of your question.

在内部,引用是使用指针实现的,但这超出了您的问题范围。

References have restrictions over other types in C++ - for example, you must always initialize a reference to "refer" to a real object when you create it, while a pointer may point to memory which is invalid, or uninitialised.

引用对c++中的其他类型有限制——例如,在创建一个实际对象时,必须初始化一个引用来“引用”它,而指针可能指向无效或未初始化的内存。

Pointer to a reference

This doesn't exist. As stated earlier, a reference is merely an alias to another object. You can't "point" to a reference, because it isn't an object in itself but merely another name for a real object.

这并不存在。如前所述,引用只是另一个对象的别名。你不能“指向”一个引用,因为它本身不是一个对象,而是一个真实对象的另一个名称。

Of course, you can have a pointer to the object that a reference is referring to. But now we are back in vanilla pointer territory.

当然,可以有指向引用所指对象的指针。但现在我们又回到了香草指针领域。

Note about parameters

When you pass a parameter by value to a method or routine, you are essentially passing a "copy" of the object to the method. Any changes you make to the value within the routine will be lost when the routine returns, because the parameter will be treated as a local variable in the context of the routine.

当您将参数按值传递给方法或例程时,实际上是将对象的“拷贝”传递给方法。当例程返回时,您对例程中的值所做的任何更改都将丢失,因为参数将在例程的上下文中作为局部变量处理。

If you want to modify a parameter which is passed in so the client (calling) code can access the change, you must pass the parameter by pointer or by reference.

如果要修改传入的参数,因此客户端(调用)代码可以访问更改,则必须通过指针或引用传递参数。

For example:

例如:

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;
}

Let's now say that your method wants to allocate memory for a pointer. You could be tempted to do this:

现在我们说,您的方法希望为指针分配内存。你可能会这么做:

void myMethod4(int* myValue)
{
    // Warning: You will lose the address of the allocated
    // memory when you return!
    myValue = new int[5];
}

But remember, you are modifying the copy of the pointer value here, not the real pointer value. Since you are wanting to modify the pointer in this routine, and not the value that the pointer "points" to, you need to pass it in as a "pointer to a pointer" or a "reference to a pointer":

但是请记住,您正在修改指针值的副本,而不是真正的指针值。由于您希望修改这个例程中的指针,而不是指针指向的值,所以需要将其作为“指向指针的指针”或“指向指针的引用”传递进去:

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];
}

In these bottom 2 examples, the code which is calling myMethod5 and myMethod6 will correctly get the memory address of the newly-allocated memory via the myValue parameter pointer or reference.

在下面两个示例中,调用myMethod5和myMethod6的代码将通过myValue参数指针或引用正确地获取新分配内存的地址。

#3


9  

There is no such thing as a pointer to a reference.

没有指向引用的指针。

#4


5  

A reference is an abstraction away from pointers. References are a bit harder to screw up, especially for novices, and are a bit more high level.

引用是一种脱离指针的抽象。参考文献有点难搞砸,尤其是对新手来说,而且要高一些。

You don't need references. You can always use pointers. However, sometimes code can be easier to read with them.

你不需要引用。你可以一直使用指针。然而,有时代码可以更容易与它们一起阅读。

A typical beginner example is a linked list. Imagine you have a variable called "list" that contains a pointer to the first one. If you wanted to add something to the head, you'd need to give your add() a double pointer, since it needs to be able to modify "head". However, you can use a reference to a pointer instead. Here, we want to use pointers in the list itself since we'll be mutating them, but the add() function will be clearer if we pass in a reference to the head of the list instead of a double pointer.

一个典型的初学者例子是链表。假设您有一个名为“list”的变量,其中包含指向第一个的指针。如果您想向head添加一些东西,您需要给add()一个双指针,因为它需要能够修改“head”。但是,您可以使用指针的引用。在这里,我们希望在列表本身中使用指针,因为我们将对它们进行修改,但是如果我们将引用传递给列表的头部而不是双指针,那么add()函数将更清晰。

They're simply a style choice. If you're working on a larger project, you should go with the style of the project. If not, you can use whatever you feel is preferable. You should, however, be comfortable using all styles if you even hope to be a mildly successful C++ programmer.

它们只是一种风格的选择。如果你在做一个更大的项目,你应该遵循项目的风格。如果没有,你可以用你认为更好的。但是,如果您甚至希望成为一个稍微成功的c++程序员,那么您应该对使用所有样式感到放心。

It is also worthwhile that you can't have a pointer to a reference. This is because references are really just another name for another variable, which may be in some other scope. Having a pointer to a reference doesn't make sense. What you'd really want is just a pointer to whatever the original data was, no references involved.

同样值得注意的是,您不能有指向引用的指针。这是因为引用实际上只是另一个变量的名称,它可能在其他的范围内。有指向引用的指针是没有意义的。你真正想要的只是一个指向原始数据的指针,不涉及任何引用。

#5


4  

It is important to note that although a reference is not an object and therefore does not have an accessible address, a reference can be contained within an object and the containing object does have an address.

需要注意的是,虽然引用不是对象,因此没有可访问的地址,但是引用可以包含在对象中,并且包含的对象确实有地址。

struct contains_ref
{
     int& ref;
     contains_ref(int& target) : ref(target) {}
};

The "reference is an alias" explanation is not incorrect, but is often accompanied by misleading claims. A reference is not equivalent to the original object. It has its own lifetime, determined by the scope or object that contains it, and not the object it refers to. And a reference can outlive an object and be used to refer to a new object created at the same address.

“引用是别名”的解释并非不正确,但往往伴随着误导性的声明。引用并不等同于原始对象。它有自己的生命周期,由包含它的范围或对象决定,而不是它引用的对象。一个引用可以比一个对象活得长,并且可以用来引用在同一个地址创建的新对象。

Treat a reference as what it really is -- an abstraction around a pointer that excludes null as a valid value, and prevents reseating1 -- and not something magic. The only unusual property of a reference that isn't derived from its pointer nature is lifetime extension of temporaries.

把引用当作它真正的样子——一个围绕指针的抽象,它将null排除为一个有效值,并防止reseating1——而不是什么神奇的东西。引用的唯一不同寻常的属性不是从它的指针属性派生出来的,它是临时变量的生命周期扩展。


1Actually this is a consequence of the fact that C++ doesn't provide any syntax for referring to the reference itself rather than its target. All operators, including the assignment operator, are simply applied to the target.

实际上,这是由于c++没有提供任何语法来引用引用本身而不是它的目标。所有操作符(包括赋值操作符)都只应用于目标。

#6


0  

Just try and see for yourself what is each thing holding. The sample program simply prints the value for an int and the addresses of different entities:

试着自己看看每件东西都装了些什么。示例程序仅打印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;
}

Output:

输出:

myInt is 42
ptr_to_myInt is bffff858
ptr_to_myInt_ref is bffff858
&ptr_to_myInt is bffff854

So, the pointer to the int and the pointer to the reference of the int are exactly the same thing. This is obvious from the code, because the pointer to a reference is simply another way of aliasing a pointer (it is saying "hold the following address for me").

所以指向int的指针和指向int引用的指针是完全相同的。从代码中可以明显看出这一点,因为指向引用的指针仅仅是另一种别名指针(它的意思是“为我保留以下地址”)。

Now, the pointer also needs some space in memory, and if you print the reference to this pointer (the last printf statement) it simply indicates the place in memory where the pointer resides.

现在,指针还需要内存中的一些空间,如果您将引用打印到这个指针(最后的printf语句),它只会指示指针所在的内存中的位置。