2010-02-24 54 views
26

可能重复:
Difference between pointer variable and reference variable in C++引用与实现中的指针有什么不同?

我阅读的书 “里面的C++对象模型”,由大师Stanley Lippman。令我百思不解的是对象的“引用”和“指针”的对象之间的差异。我知道一个引用必须在声明时被初始化,而一个指针可以留给以后的初始化。但我想知道它们之间的物理实现差异。

为什么要有“参考”的机制;它不是与指针的功能重叠吗?在什么情况下我们应该使用指针以外的参考?非常感谢。

+0

对不起,踩着你的脚趾,hobodave。我同意你的标题更好。 – GManNickG 2010-02-24 02:13:53

+0

可能重复:http://stackoverflow.com/questions/57483/difference-between-pointer-variable-and-reference-variable-in-c – 2010-02-24 02:19:43

+0

感谢,布赖恩和GMAN。 – smwikipedia 2010-02-24 02:31:27

回答

7

大多数参考都是使用指针变量实现的,即参考通常占用一个字的内存。 然而,优化器可以消除纯粹在本地使用的引用,并且经常会这样做。例如:

struct S { int a, int b[100]; }; 
    void do_something(const vector<S>& v) 
    { 
    for (int i=0; i<v.size(); ++i) { 
     int*& p = v[i].b; 
      for (int j=0; j<100; ++j) cout <<p[j]; 
    } 

在这种情况下,对不需要被存储在存储器(可能只是存在于一个寄存器,也许它消失在指令)。

+1

Prasoon,你有一个重复在那里,我想你需要在你的答案中删除“are implements”。另外,“它”应改为“那是” – legends2k 2010-02-24 02:36:23

+1

@ legends2k:谢谢!完成。 – 2010-02-24 02:37:18

+3

这是有点误导,因为本地使用的指针也可以被优化器消除。 – Mehrdad 2015-11-22 09:33:14

1

参考是在大多数情况下在内部指针(存储或传递给函数特别是当)。它们的操作方式与指针的操作方式相同,只要使用对两者都有效的操作即可。

额外的检查和语法糖引用是严格意义上的编译时间功能,很像类型系统(有关数据类型的大部分信息在编译过程中丢失)。

的重要差异是

  • 参考总是指向的对象(不能为NULL)
  • 的参考点到一个对象只(不象一个指针数组可能)
  • 参考必须是初始化初始化(否则会出现编译错误)
  • 初始化后指向其他地方的引用无法修改
  • 删除引用指向的对象ce,而参考变量保持活着,是未定义的行为(但不是编译错误)
+0

+1。将UB展开为未定义的行为。 – 2010-02-24 02:20:09

+0

谢谢,Tronic。我从你那里得知,“参考和类型系统是编译时功能”。 – smwikipedia 2010-02-24 02:29:28

0

引用对你来说只是一个C++程序员。编译器无论如何都将引用实现为指针,所以它不关心你是否使用指针或引用。

正如你所说,引用在许多情况下都比指针更好,因为它们可以保护被调用方免受不良输入(坏指针经常导致seg错误),并且您也可以将它们设置为const,这样可以提供更好的保护,设置一个指向const的指针。

+0

...似乎还是另一种语法糖。谢谢,monoceres。 :D – smwikipedia 2010-02-24 02:30:53

0

C++的引用在很大程度上是一个句法机制。

考虑

int x; 
int &y = x; 
int *z = &x; 

表达式(* z)是一样的东西(Y)​​。

除了保存你输入几个字符之外,这里唯一的语言事件是,因为引用不能为空。

+0

-1并非如此,C++标准并没有规定如何实现引用(尽管这通常是如何实现的)。此外,你可以破解一个引用,使其显示为空,例如“int&y = *(int *)0;” (但这样做是非常糟糕的编码)。 – 2010-02-24 04:09:57

+0

@格兰彼得斯:我没有如何实施,我说他们如何有效地工作。 – bmargulies 2010-02-24 12:04:41

+0

是的,我想你没有。我以前一定读过太多的东西(可能是因为读了这么多不同的答案),我会收回我的-1,但是似乎并不认为我们的观点可能会改变(只有当答案改变时我们才能改变我们的观点投票) – 2010-02-24 12:32:59

8

的引用可以被认为是作为隐含解引用常量指针(注意这一点)。一旦参考,总是一个参考。它允许轻松编写代码。除非有,否则你会引入移动语义和r值引用。该标准并没有规定如何实施引用,因为它没有规定如何实施指针。大多数情况下,指针与对象的地址是同义的。

5

如果可以,请使用引用,当需要时使用引用。原因你需要使用一个指针:

  1. 有可能不是一个对象为它指向(空指针,没有空引用)。
  2. 您可能需要在其生命周期中引用不同的对象。
  3. 您可能需要引用整个对象数组(但std::vector通常更好)。

但是,有一些情况下,两者的使用并不真正重叠,而且您根本无法替代另一个。对于一个明显的例子,考虑下面的代码:

template <class T, size_t N> 
size_t size(T(&matrix)[N]) { 
    return N; 
} 

这可以让你找到一个数组的大小:

int array1[some_size]; 
int array2[some_other_size]; 

size_t n = size(array1); // retrieves `some_size` 
size_t m = size(array2); // retrieves `some_other_size` 

...但它只是如果你试图通过将不能编译它的指针:

int *x = new int[some_size]; 

size_t n = size(x); // won't compile 

在最好的似乎毫无意义的写代码来获得一个指针时,其点的一部分,是拒绝被传递的指针。其中

0

一个实例参考应当被用来代替指针:

enum day 
{ 
    Mon, Tue, Wed, Thu, Fri, Sat, Sun 
}; 

day d; 

day *operator++(day *d); 

操作员++可使用++&d,这看起来并不该直观被调用。这里的一个大问题是,所有重载的运算符函数必须是类的成员,或者具有类型T的参数,T &或T const &,其中T是类或枚举类型。所以,在这种情况下, day *operator++(day *d);甚至不会编译。

它采用基准即

day &operator++(day &d); 

这可以简单地援引为++d;

这是从那里我得到这个例子很好article工作正常。

欢呼声

+0

你不能重载内置类型的运算符,如指针 – 2010-02-24 04:09:24

+0

那么,这就是为什么它不能被实现。我的答案包括那部分。 – Arnkrishn 2010-02-24 04:32:32

1

指针是一个不同的值,与指向的数据无关。(即使在内存中的地址0x12345678处没有有意义的数据,数字0x12345678作为指针值也是有意义的。)因为它是一个独特的值,所以它可以独立操作:可以对其进行递增或递减,将其与其他指针进行比较,并将其值显示在屏幕上,而不管它是否实际上“指向任何东西”。

你不能用一个参考做任何的那些东西,因为它不是一个独特的价值。它是一个别名,一个替代名称(可能在不同的范围内)用于某些现有值。这使得引用更易于使用(因为它们的行为就像它们引用的对象一样,不需要解引用),并且也更安全(因为如果使用得当,它们总是引用对象;不存在悬挂或空引用)。

这可能是真实的引用通常会转换成编译后的机器代码的指针,但你应该想到的是,因为编译器,不能保证的私人实现细节。引用是他们自己的概念和自己的用例,而不仅仅是指针的不同方式。

当你需要一个不同的类指针值可以操纵和独立于数据的检查它指向,使用指针(或,优选地,智能指针类)。当您只需要一种方法来获取存在于一个范围内的值并使其在另一个范围内可用时(例如,将对象传递给函数而不复制它),请使用引用。

1

参考是变相的指针,或者至少是把它们的安全方法。

其中一个原因是因为C和C++没有“var”参数,就像在Pascal等中一样。使用引用给出的东西非常接近,但与“var”不同,它也可以在其他地方使用 - 例如给你一个快速的简写别的东西......

int& alias = thing.blah [foo]->bar; 
handle (alias, alias+1, alias*2); 

还提及由很多功能恢复,这意味着功能的“结果”可以写入和读取,在..

std::deque<int> mydeque; 
mydeque.push_back (1); 
mydeque.back() += 1; // increment the top item on the stack 

使用指针可以实现相同的功能,但引用更方便。通常的术语是“syntactic sugar”。

有关引用的一个有用的(但不是完全可靠的)事实是,你不太可能意外地改变底层指针,因为它需要多一点的工作访问的指针,而不是指向的值。这对于选择有用的提示 - 使用在代码中创建最少杂乱的提示。