开发者

How is a reference different from a pointer in implementation? [duplicate]

This question already has answers here: Closed 12 years ago.

Possible Duplicate:

Difference between pointer variable and reference variable in C++

I am reading about the book "Inside the C++ Object Model" by Stanley Lippman. What puzzles me is the difference between a "reference" of an object and a "pointer" to an object. I know that a reference must be initialized when declared, while a pointer could be left for later initialization. But I want to know the physical implementation difference between them.

Why should there be the "reference" mechanism; isn't it overlapping the function of a pointer? Under what circumstance should we use reference other than pointer? Many thanks.

10:48 AM 11/20/2021

Reference is from t开发者_StackOverflowhe semantic perspective.

Pointer is from the implementation perspective.

It's kind of like the relation between what and how.


A reference can be thought of as an implicitly de-referenced constant pointer (note this). Once a reference, always a reference. It allows for ease of writing code. Unless of course, you bring in move semantics and r-value references. The standard doesn't mandate how references should be implemented just as it does not mandate how pointers should be implemented. Most of the time though, pointers are synonymous with addresses of objects.


Most references are implemented using a pointer variable i.e. a reference usually takes up one word of memory. However, a reference that is used purely locally can - and often is - eliminated by the optimizer. For example:

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

In this case, p needs not be stored in memory (maybe it just exists in a register, maybe it disappears into the instructions).


Use references when you can, and pointers when you need to. Reasons you'd need to use a pointer:

  1. There might not be an object for it to point at (null pointer, no null references).
  2. You might need to refer to different objects during its lifetime.
  3. You might need to refer to a whole array of objects (but std::vector is usually better).

There are, however, cases where the usage of the two doesn't really overlap at all, and you simply can't substitute one for the other. For one obvious example, consider the following code:

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

This allows you to find the size of an array:

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`

...but it simply won't compile if you try to pass a pointer to it:

int *x = new int[some_size];

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

At very best it seems to make little sense to write the code to receive a pointer when part of its point is to reject being passed a pointer.


References are in most cases internally pointers (especially when stored or passed to functions). They operate the same way as a pointer would, as long as only operations valid for both are used.

The extra checks and syntactic sugar for references is strictly a compile-time feature, much like the type system (most information about data types is lost during compilation).

The important differences are

  • Reference always points to an object (cannot be NULL)
  • Reference points to one object only (not to an array like a pointer might)
  • Reference must be initialized initially (otherwise you get a compile error)
  • Reference cannot be modified after initialization to point somewhere else
  • Deletion of the object pointed to by a reference, while the reference variable stays alive, is Undefined Behavior (but not a compile error)


References are pointers in disguise, or at least that's a safe way to think of them.

One reason for them is because C and C++ don't have "var" parameters, as in Pascal etc. Using a reference gives you something very close to that, but unlike "var", it can also be used elsewhere - e.g. to give you a quick shorthand for something else...

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

References are also returned by a lot of functions, meaning the "result" of the function can be written to as well as read, as in...

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

The same functionality could be achieved using a pointer, but a reference is more convenient. The usual term is "syntactic sugar".

A useful (but not completely reliable) fact about references is that you're less likely to accidentally change the underlying pointer, since it takes a bit of work to access that pointer rather than the pointed-to value. This is a helpful hint to choosing - use the one that creates the least clutter in your code.


A pointer is a distinct value, independent of the data it points to. (The number 0x12345678 is meaningful as a pointer value even if there's no meaningful data at address 0x12345678 in memory.) Because it's a distinct value, it can be manipulated on its own: you can increment or decrement it, compare it against other pointers, and print its value to the screen, regardless of whether it actually "points to anything."

You can't do any of those things with a reference because it's not a distinct value. It's an alias, an alternate name (possibly in a different scope) for some existing value. This makes references easier to use (since they act just like the object they refer to, no dereferencing needed), and also safer (since, if used properly, they always refer to an object; there's no such thing as a dangling or null reference).

It may be true that references typically get translated into pointers in the compiled machine code, but you should think of that as a private implementation detail of the compiler, not a guarantee. References are their own concept with their own use-cases, not just a different way of working with pointers.

When you need a distinct pointer-like value that you can manipulate and examine independently of the data it points to, use a pointer (or, preferably, a smart-pointer class). When you just need a way to take a value that exists in one scope and make it available in another scope (e.g. passing an object into a function without copying it), use a reference.


References are just good for you as a C++ programmer. The compiler implements references as pointers anyway so it doesn't care if you use a pointer or a reference.

References is, like you said, better than pointers in many cases because they protect the callee from bad input (bad pointers often results in seg faults) and you can also set them to const, which provides better protection from changes than setting a pointer to const.


C++ references are largely a syntactic mechanism.

Consider

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

The expression (*z) is the same thing as (y).

Aside from saving you typing a few characters, the only language thing going on here is that as reference cannot be null.


One example where reference ought to be used instead of pointers:

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

day d;

day *operator++(day *d);

The operator ++ can be invoked using ++&d, which does not look that intuitive.

One big catch here is that all overloaded operator functions must either be a member of a class, or have a parameter of type T, T &, or T const &, where T is a class or enumeration type. So, in this case day *operator++(day *d); won't even compile.

It works fine using reference i.e.

day &operator++(day &d);

which can be invoked simply as ++d;

Here is a nice article from where I got this example.

cheers

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜