参考如何与实现中的指针不同?

时间:2010-02-24 02:06:18

标签: c++ pointers language-design

  

可能重复:
  Difference between pointer variable and reference variable in C++

我正在阅读Stanley Lippman撰写的“Inside the C ++ Object Model”一书。令我困惑的是对象的“引用”和对象的“指针”之间的区别。我知道引用必须在声明时初始化,而指针可以留待以后初始化。但我想知道它们之间的物理实现差异。

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

9 个答案:

答案 0 :(得分:9)

可以将引用视为隐式取消引用的常量指针(请注意这一点)。一旦参考,总是一个参考。它允许轻松编写代码。当然,除非您引入移动语义和r值引用。该标准没有强制要求如何实现引用,因为它没有强制如何实现指针。大多数情况下,指针与对象的地址同义。

答案 1 :(得分:8)

大多数引用是使用指针变量实现的,即引用通常占用一个字的存储器。 但是,纯粹本地使用的引用可以 - 通常是 - 由优化器消除。例如:

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

在这种情况下,p不需要存储在内存中(可能它只存在于寄存器中,也许它会消失在指令中)。

答案 2 :(得分:6)

尽可能使用引用,并在需要时使用指针。您需要使用指针的原因:

  1. 可能没有对象指向(空指针,没有空引用)。
  2. 您可能需要在其生命周期内引用不同的对象。
  3. 您可能需要引用整个对象数组(但std::vector通常更好)。
  4. 然而,有两种情况下两者的用法根本不重叠,而你根本无法用另一种替代。举一个明显的例子,请考虑以下代码:

    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
    

    当它的一部分要拒绝被传递指针时,编写接收指针的代码似乎没有多大意义。

答案 3 :(得分:1)

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

引用的额外检查和语法糖严格来说是编译时功能,非常类似于类型系统(编译期间大多数有关数据类型的信息都会丢失)。

重要的区别是

  • 引用始终指向一个对象(不能为NULL)
  • 引用仅指向一个对象(不指向像指针那样的数组)
  • 最初必须初始化引用(否则会出现编译错误)
  • 初始化后,无法修改引用以指向其他位置
  • 引用所指向的对象的删除,而引用变量保持活动状态,是Undefined Behavior(但不是编译错误)

答案 4 :(得分:1)

指针是一个不同的值,与它指向的数据无关。 (数字0x12345678作为指针值是有意义的,即使内存中的地址0x12345678没有有意义的数据。)因为它是一个独特的值,它可以自己操作:你可以递增或递减它,将它与其他指针进行比较,并将其值打印到屏幕上,无论它是否“指向任何东西。”

你不能用引用做任何这些事情,因为它不是一个明确的值。对于某些现有值,它是别名,备用名称(可能在不同的范围内)。这使得引用更容易使用(因为它们就像它们引用的对象一样,不需要解除引用),也更安全(因为,如果使用得当,它们总是引用一个对象;没有悬空或空引用这样的东西)。

引用通常可以转换为已编译的机器代码中的指针,但您应该将其视为编译器的私有实现细节,而不是保证。引用是他们自己的概念和他们自己的用例,而不仅仅是使用指针的不同方式。

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

答案 5 :(得分: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”。

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

答案 6 :(得分:0)

作为C ++程序员,引用对你有好处。编译器无论如何都将引用实现为指针,因此它不关心你是否使用指针或引用。

与你说的一样,引用在许多情况下比指针更好,因为它们保护被调用者免受错误输入(坏指针经常导致seg错误),你也可以将它们设置为const,这提供了比设置更好的保护指向const的指针。

答案 7 :(得分:0)

C ++引用主要是一种语法机制。

考虑

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

表达式(* z)与(y)相同。

除了节省你输入几个字符之外,这里唯一的语言就是参考不能为空。

答案 8 :(得分:0)

应该使用引用而不是指针的一个例子:

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

day d;

day *operator++(day *d);

可以使用++&d调用operator ++,这看起来不那么直观。

这里的一个重要问题是所有重载的运算符函数必须是类的成员,或者具有类型为T,T&amp;或T const&amp;的参数,其中T是类或枚举类型。所以,在这种情况下 day *operator++(day *d);甚至不会编译。

使用引用即

可以正常工作
day &operator++(day &d);

可以简单地调用++d;

这是一个很好的article,我从这里得到了这个例子。

欢呼声