86

There seems to be many relavent questions talking about pointer vs. reference, but I couldn't find what I want to know. Basically, an object is passed in by a reference:

funcA(MyObject &objRef) { ... }

Within the function, can I get a pointer to that object instead of the reference? If I treat the reference objRef as an alias to the MyObject, would &objRef actually give me a pointer to the MyObject? It doesn't seem likely. I am confused.

Edit: Upon closer examination, objRef does give me back the pointer to object that I need - Most of you gave me correct info/answer, many thanks. I went along the answer that seems to be most illustrative in this case.

Oliver
  • 3,592
  • 8
  • 34
  • 37
  • 1
    Why do you need a pointer from a reference? – Griwes Feb 13 '12 at 16:02
  • 3
    @Griwes: Off the top of my head, pointer math may be desired or another API may want a pointer. – Drew Dormann Feb 13 '12 at 16:05
  • 1
    what if you just get the address of the reference? `&objRef` – vulkanino Feb 13 '12 at 16:06
  • @DrewDormann, what, pointer math on address of object passed by reference? Doesn't look like good design to me. – Griwes Feb 13 '12 at 16:06
  • 4
    An example would be a reference is passed in, the parsing of binary stream such as `reinterpret_cast` requires a pointer type instead. – Oliver Feb 13 '12 at 16:12
  • As ugly as it seems, and as bad design as it might be indicative of, some times for performance or scale reasons it's your only option to deal with external APIs. It's also rather useful foundation knowledge to learn for reverse engineering/hacking. –  Dec 31 '14 at 14:20

6 Answers6

134

Yes, applying the address-of operator to the reference is the same as taking the address of the original object.

#include <iostream>

struct foo {};

void bar( const foo& obj )
{
  std::cout << &obj << std::endl;
}

int main()
{
  foo obj;
  std::cout << &obj << std::endl;
  bar( obj );

  return 0;
}

Result:

0x22ff1f
0x22ff1f
Praetorian
  • 106,671
  • 19
  • 240
  • 328
45

Any operator applied to a reference will actually apply to the object it refers to (§5/5 [expr]); the reference can be thought of as another name for the same object. Taking the address of a reference will therefore give you the address of the object that it refers to.

It as actually unspecified whether or not a reference requires storage (§8.3.2/4 [dcl.ref]) and so it wouldn't make sense to take the address of the reference itself.

As an example:

int x = 5;
int& y = x;
int* xp = &x;
int* yp = &y;

In the above example, xp and yp are equal - that is, the expression xp == yp evaluates to true because they both point to the same object.

Joseph Mansfield
  • 108,238
  • 20
  • 242
  • 324
  • 8
    The reference is NOT simply another name for the same object (the lifetime of a reference is distinct from the lifetime of the object it points to). However, your sample code will work, because using any operator on a reference actually uses the target object instead. – Ben Voigt Feb 13 '12 at 16:13
  • @BenVoigt. There is no legal way for a reference to not live as long as the object. deleting at dynamic storage duration object that is referenced or returning a reference of an automatic storage duration object both invoke undefined behavior. – Martin York Feb 13 '12 at 16:47
  • 1
    @Loki: What? A reference can definitely "not live as long as the object", and it can also *outlive* the object. Using a reference after the lifetime of its original target object has ended is undefined behavior under all but very specific and restricted conditions. – Ben Voigt Feb 13 '12 at 16:53
  • @BenVoigt: Show me a legal way to do that then. – Martin York Feb 13 '12 at 18:29
  • 1
    @Loki: Here, demonstration of reference and object having totally distinct lifetime: http://ideone.com/iQFMF – Ben Voigt Feb 13 '12 at 21:47
  • @BenVoigt: Of course you can break it with undefined behavior. But there is little point in talking about undefined behavior (once you stray into that arena it does not rally matter what you do). – Martin York Feb 13 '12 at 22:49
  • @Loki: What undefined behavior? All of that code is standard-compliant. But ask your own question. The comments are not the right place for me to try to explain this. – Ben Voigt Feb 13 '12 at 22:59
  • 1
    @BenVoigt: After you call the destructor the object is destroyed. It no longer exists. Thus you are trying to justify your assertions using undefined behavior. All pointless. I don't have a question. I am just calling you out on your incorrect statement in the first comment. A reference is nothing more than an alias. All the affects you are describing are simply the result of undefined behavior or an implementation side-effect. – Martin York Feb 14 '12 at 04:33
  • @Loki: Clearly I'm going to have to write a blog article explaining this. The code is well-defined according to the standard. A reference is an alias to a memory location, not to an object. But these comments are not a suitable place for me to explain. – Ben Voigt Feb 14 '12 at 13:31
  • 3
    @Ben: Yes I always found one sided arguments (blogs) are the greatest way to get to the truth. You said it yourself a reference is an alias. Alias => 'Another Name'. Yes. perfectly legal code can still lead to undefined behavior. What I am saying is valid code (ie that does not invoke undefined behavior) a reference will not last longer than an object it refers too and acts as another name for an object. You are saying: A reference behaves like a pointer when we invoke undefined behavior. I say yep, so what. – Martin York Feb 14 '12 at 15:25
  • @Loki: Are we discussing my example, which contains no undefined behavior (assuming that `sizeof (something) <= 50`, and [here's a variant that removes the need for that assumption](http://ideone.com/5hHwZ)), or some code with undefined behavior that you haven't even bothered to share with the rest of us? – Ben Voigt Feb 14 '12 at 15:30
  • @BenVoigt: I so disagree. **AS** I pointed out above. By calling the destructor you are manually destroying the object. Any reference to it now is undefined behavior. Your argument only holds as long as you consider undefined behavior normal. Which I don't. – Martin York Feb 14 '12 at 15:33
  • @Loki: As I requested earlier, ask a question and I will give you the Standard citation and explanation that makes this code well-defined. – Ben Voigt Feb 14 '12 at 15:37
  • @BenVoigt: I have no question. Just calling you on (on what I believe is) your incorrect comment. If you have a standard reference that proves your side post it. If I agree on its interpretation I am more than willing to say you were correct and remove my other comments. – Martin York Feb 14 '12 at 15:48
  • @Loki: I can't fit a quote in a comment, and I also feel I deserve the reputation for doing the legwork/research for you. 3.8p7, on page 71 of n3290, and page 50 of C++03. – Ben Voigt Feb 14 '12 at 15:52
  • You missed the second condition: the new object is of the same type as the original object (but you can easily fix that in your example). But once you do: we have an object that we refer to by a reference. If we manually destroy the object with the destructor and then create the exact object again are you really creating a new object. You may argue that but I would just say it is the same object and does not change the fact that the reference is simply an alias. As far as the user of the object/reference is concerned it is the same. No points for bad interpretation. :-) – Martin York Feb 14 '12 at 16:12
  • 2
    @Loki: I'm replacing an `int` with another `int` in the exact same location, no problems there. And clearly it's a new object (destructor ran on the old one, constructor ran for the new one). The standard also says it's a new object. I can't see that your new-found approach to this (replacing the now-defeated claim of undefined behavior) makes any sense at all, since it completely removes any meaning of the term "object lifetime". Seems more like an desperate attempt to excuse your repeated attacks on my comment and example. – Ben Voigt Feb 14 '12 at 16:33
  • @BenVoigt: The first problem is solved by just making the new object an int (you arguments holds slightly more water then but otherwise it is invalid). But I disagree with your interpretation. Sorry if you find that offensive. You are just plain wrong and nothing you have said changes my mind. Your attempts to steer the argument to an irrelevant direction just confirm to me that your arguments are on shaky ground to start with. – Martin York Feb 14 '12 at 16:38
  • 1
    @Loki: The new object IS an `int`, per line 44. You're just demonstrating that you haven't either read nor understood my example. And there doesn't even have to be a new object at all. Read paragraph 6 of the same section. A C++ reference is bound to a memory location, not an object. Just like a pointer. The wording of the Standard supports that, and you haven't a shred of evidence to the contrary. – Ben Voigt Feb 14 '12 at 16:43
  • @Loki: Plus, there's still that absolutely ridiculous claim you made that "There is no legal way for a reference to not live as long as the object." – Ben Voigt Feb 14 '12 at 16:45
  • @BenVoigt: Sorry I mean make both the same type (sorry badly typed). `something` is not an `int`. Condition one they have to overlay exactly. Condition two they need to be the same type. – Martin York Feb 14 '12 at 16:54
  • @BenVoigt: I am sorry you seem to be getting upset about this discussion nothing personal in it. Where I come from spirited disagreements are a good thing not negative. It means we can argue to get resolution. – Martin York Feb 14 '12 at 16:55
  • @BenVoigt: I stand by my original statement. `There is no legal way for a reference to not live as long as the object.` (the key is legal). Of course you can do it using undefined behavior. But I really don't care about that. Your example **when fixed** (shows you can re-new the object) but I disagree that the changes the intent or meaning of my statement. Which is designed to call you on your first statement. `The reference is NOT simply another name for the same object`. – Martin York Feb 14 '12 at 16:58
  • @Loki: The old and new objects are exactly the same type (`int`), and both are "most-derived" (neither is a base subobject). One is a member subobject, but that is allowed. If you'd read the comments in the example code, you'd already have seen this. It's become clear to me that the old adage "You can lead a horse to water, but you can't make him drink" applies in this situation. Trying to teach you the complexities of C++ is futile, so I shan't waste any more time trying. – Ben Voigt Feb 14 '12 at 17:08
  • @BenVoigt: Yes insults prove your point so well. :-) Sorry but I could not let you get away with speaking such fundamental untruths. Since this site is full of beginners I felt it was important to point out your original mistake. I know you are good C++ programmer I have read your answers (but your youth and inexperience are obviously coming out here in your inability to argue you point well ). I would be quite willing to yield if you could prove it, but you have yet to do so. A reference **is** an alias and **not** a fancy pointer. – Martin York Feb 14 '12 at 17:20
  • @BenVoigt: I am sorry I let the argument go down a fruitless side track with my (lets admit it badly phrased but still fundamentally correct) original counter argument and your futile attempt to prove that wrong. But you are still wrong: 'A reference **is** an alias (ie another name for a variable).` – Martin York Feb 14 '12 at 17:30
  • 1
    @Loki: I made that claim in context. Do you, now informed by the Standard, agree or disagree with "the lifetime of a reference is distinct from the lifetime of the object it points to" (which I said in my original comment you took issue with)? – Ben Voigt Feb 14 '12 at 17:57
  • Upvoted for the standard refs, which make this superior to the accepted answer. ...shame about the comments. – underscore_d Apr 11 '16 at 22:47
  • 2
    Agreed. For anyone that encounters this in the future, and gets curious, I'd just like to point out that § 3.8.1 (**[basic.life]/1**) explicitly states that for an object of type `T`, its lifetime begins when "storage with the proper alignment and size for type `T` is obtained, and if the object has non-trivial initialization, its initialization is complete.", and that its lifetime ends when "if `T` is a class type with a non-trivial destructor (12.4), the destructor call starts, or the storage which the object occupies is reused or released." (According to the C++14 standard.) – Justin Time - Reinstate Monica Nov 21 '16 at 00:07
  • 1
    So, the standard thus states that even "we manually destroy the object with the destructor and then create the exact object again", the result is still a new, distinct object. Just wanted to clarify that, so nobody can potentially be confused by it. – Justin Time - Reinstate Monica Nov 21 '16 at 00:09
29

The general solution is to use std::addressof, as in:

#include <type_traits>

void foo(T & x)
{
    T * p = std::addressof(x);
}

This works no matter whether T overloads operator& or not.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 2
    Excellent point, since the reference _is_ the referred object, one needs to be careful if said object might overload `operator &`... rare but invaluable for proxy classes... one day I'll resume that project where I needed this! – underscore_d Apr 11 '16 at 22:53
8

Use the address operator on the reference.

MyObject *ptr = &objRef;
Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
7

Use the address-of (&) operator on the reference.

&objRef

Like any other operator used on a reference, this actually affects the referred-to object.

As @Kerrek points out, since the operator affects the referred-to object, if that object has an overloaded operator& function, this will call it instead and std::address_of is needed to get the true address.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
-3

In C++, a reference is a restricted type of pointer. It can only be assigned once and can never have a NULL value. References are most useful when used to indicate that a parameter to a function is being Passed by Reference where the address of the variable is passed in. Without a Reference, Pass By Value is used instead.

damson
  • 2,635
  • 3
  • 21
  • 29
  • No. A reference is an alias to an existing object. Thinking of it as a fancy pointer will just confuse you when you start doing more complex stuff. – Martin York Feb 13 '12 at 16:13
  • @Loki: A reference is a handle. So is a pointer. Both of them consume storage (unless optimized away) and have distinct lifetime from the referred-to object. The similarities greatly outweigh the differences. – Ben Voigt Feb 13 '12 at 16:16
  • @BenVoigt: Careful on terminology. Handle has other meanings in comp sci. But I take your point. But I disagree with your opinion. Also note 8.3.2 References [dcl.ref] para 4 it is unspecified whether or not a reference requires storage If a reference is like a pointer why can't I get a reference to my reference (its because it does not exist). It is simply an alias. – Martin York Feb 13 '12 at 16:36
  • @damson: Yes there a lots of crap references on the web. Pick up a copy of the standard here: http://stackoverflow.com/a/4653479/14065 – Martin York Feb 13 '12 at 16:39
  • Just look at this: [reference](http://www.dgp.toronto.edu/~patrick/csc418/wi2004/notes/PointersVsRef.pdf) to know what is the comportment of a reference and this: [pointers](http://www.cplusplus.com/doc/tutorial/pointers/) cause your don't know what is a pointer. – damson Feb 13 '12 at 16:51
  • @damson: Obviously your reference is wrong. From the standard: [dcl.ref] para 4: it is unspecified whether or not a reference requires storage On the other hand a pointer does require storage and you can take its address to prove it. – Martin York Feb 14 '12 at 17:22