4

This looks a very basic topic but very important to me.

The following example shows that the address of a reference variable is equal to the address of the original variable. I know this is what we can expect from the concept of C/C++. However, is it always guaranteed that these addresses are equal under any circumstance?

#include <iostream>
#include <vector>
#include <string>

class Point
{
public:
    double x,y;
};

void func(Point &p)
{
    std::cout<<"&p="<<&p<<std::endl;
}

int main()
{
    std::vector<Point> plist;
    plist.push_back({1.0,4.0});
    plist.push_back({10.0,20.0});
    plist.push_back({3.0,5.0});
    plist.push_back({7.0,0.4});

    std::cout<<"&plist[2]="<<&plist[2]<<std::endl;

    func(plist[2]);

    return 0;
}

Result:

&plist[2]=0x119bc90
&p=0x119bc90
ar2015
  • 5,558
  • 8
  • 53
  • 110
  • Do you have something else in mind for what they might be? – Scott Hunter Aug 22 '17 at 15:28
  • 2
    References don't have addresses. Objects have addresses. One object only has one address. A reference refers to an object it was initialised with. Not to a copy of it. – n. m. could be an AI Aug 22 '17 at 15:33
  • @n.m.: References sometimes have addresses, it's just very hard to get to them. Particularly, `&r` doesn't take the address of the reference `r` any more than `r + 1` does pointer arithmetic. The indirection is done automatically before any operation, so `&r` is similar to `&(*p)`. – Ben Voigt Aug 22 '17 at 15:38
  • Possible duplicate of [What are the differences between a pointer variable and a reference variable in C++?](https://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable-in) – Óscar Andreu Aug 22 '17 at 15:44
  • you have to consider that dont even get a guarantee that `&foo` is the adress of `foo` because `operator&` can be implemented to return whatever it likes. Whether is makes sense is of course a different question ;) – 463035818_is_not_an_ai Aug 22 '17 at 15:49

5 Answers5

4

Is always the address of a reference equal to the address of origin?

Objects have addresses. A reference is not an object and does not (necessarily) have an address. When address-of operator is applied to a reference, the result is the address of the referenced object.

is it always guaranteed that these addresses are equal under any circumstance?

Yes, it is guaranteed (unless the address-of operator is overloaded with a silly implementation).

An object that is referred by a reference is the same object as the one that is referred by that reference. An object has the same address as that object has... because it is that object :)


Now, it is possible to overload the addressof operator such that it no longer returns the actual address of that object. In that case, those two invocations could result in a different address. A demo:

struct evil {
    static evil silly;
    static bool insane;
    evil* operator&() {
        evil* bonkers = insane ? std::addressof(silly) : this;
        insane = !insane; // does this mean it is no longer insane?
        return bonkers;
    }
};

bool evil::insane = true;
foo evil::silly;

int main() {
    evil e;
    evil& ref = e;
    std::cout << &e << '\n';
    std::cout << &ref << '\n';
    std::cout << &ref << '\n';
}

Possible output:

0x7ffffbeef42d
0x600dd1
0x7ffffbeef42d
eerorika
  • 232,697
  • 12
  • 197
  • 326
4

Unfortunately, many people confuse logical and physical meaning of C++ references.

Logical level
There is a crucial thing I found for myself about C++ references:
As soon as I have initialized a reference, it becomes unpronounceable. And what I mean by "unpronounceable" is the fact that always when you name a reference in runtime executable code - you automatically get the variable it refers to, so there is no way you can touch the reference itself. Reference is just an alternative name (an alias) for a variable.

So if you have something like int i_var = 10; int& i_ref = i; no matter what executable expression you form with it, any mentioning of i_ref would actually mean i_var.

Also, some people find helpful to think of a reference as a "self-dereferencing pointer". So imagine you have a pointer int* p, but each and every time you refer to it as p you actually mean *p. For instance, p = 10 would mean *p = 10 and &p would mean &(*p) - the address of int which p is pointing too. That is how logically references work.

It applies to your code too. As soon as you have Point &p = plist[2]; (occured when you called func(plist[2])) then p and plist[2] start reference to the same thing - some Point object stored by the index of 2 in plist. So now &plist[2] and &p are absolutely equal.

Type system level
If you noticed, I used terms "runtime executable code" or "executable expression". Let me clarify.
The compiler actually knows the difference between a and b:

int a = 0;
int& b = a;

std::cout << std::boolalpha 
          << std::is_same_v<decltype(a), decltype(b)>; // -> false

As you see a and b types are different. However, std::is_same_v<decltype(a), decltype(b)> gets evaluated at compile time so i did not consider it as an "executable expression".

Physical level
Notice, that until now I did not said that the address of a reference and the address of variable being referenced are the same. Why? Because if you think logically - they are not.

References have to be implemented in some way, whether you like it or not. I believe, in the example with i_var and i_ref compiler will simply replace all i_ref with i_var and any physical representation of "reference" will never exist. On the other hand, if you store reference inside a class it is likely to be implemented with a pointer.
Although, an implementation is compiler dependent, if reference actually is a pointer under the hood, it is obvious that the address of this pointer and the address of the object it is pointing to are different.

However, why should you care? You will never know the address of reference! In any executable expression, when you say i_ref you imply i_var, remember?:)


OK, if you are really-really curious "what is the address of a reference", there is a one case when you can figure it out - when reference is a member of a class:

int main()
{
    int var = 10;
    int& real_ref = var;
    struct { int& ref; } fake_ref = { var };

    std::cout << &var       << std::endl;   // address of var
    std::cout << &real_ref  << std::endl;   // still address of var
    std::cout << &fake_ref  << std::endl;   // address of reference to var

    std::cout << sizeof var         << std::endl;    // size of var
    std::cout << sizeof real_ref    << std::endl;    // still size of var
    std::cout << sizeof fake_ref    << std::endl;    // size of reference to var

    return 0;
}

Output on x64 compiler:

000000A9272FFBA4   <- same
000000A9272FFBA4   <- same
000000A9272FFBC0   <- different
4                  <- same
4                  <- same
8                  <- different (8 on 64 bit and 4 on 32 bit compiler)
WindyFields
  • 2,697
  • 1
  • 18
  • 21
1

Where the type of the reference and the type of the variable used to initialize it are different, the address of the reference can be different from the address of the initializing variable.

e.g.

#include <stdio.h>

struct Class1
{
    int x;
};

struct Class2
{
    int p;
};

struct Class12 : Class1, Class2 {};

int main(int argc, char* argv[])
{
    Class12 p;
    Class1& r1 = p;
    Class2& r2 = p;
    
    printf("p=%p, r1=%p, r2=%p", &p, &r1, &r2);
}

When run, the output is:

p=0x7ffefcfd1a20, r1=0x7ffefcfd1a20, r2=0x7ffefcfd1a24

The address of r1 is different from r2, despite the fact the two references were initialized from the same variable.

0

is it always guaranteed that these addresses are equal under any circumstance?

yes, you are passing the reference of that Object so no copy is made, (if that is the background of the question), what you are printing is exactly the address of the original parameter by the time you call the function.

ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97
  • let's ignore the `&` operator. Could you please provide any link from C++ references for this claim? Thanks. – ar2015 Aug 23 '17 at 00:01
0

Is it always guaranteed that these addresses are equal under any circumstance?

As per the C++ standard it is unspecified whether or not a reference requires storage. On the other hand it also says that taking the address of a reference gives you the address of the referent. Hence even if the compiler chooses to have a separate storage for the reference than the referent internally, it would be guaranteed to the programmer that their addresses are the same.

Amit Rastogi
  • 926
  • 2
  • 12
  • 22
  • In the last sentences, you meant, the result of `&` operator would be the same - addresses of reference and "referent " are different. – WindyFields Aug 22 '17 at 20:36
  • let's ignore the `&` operator. Could you please bring any reference for this claim? Thanks. – ar2015 Aug 23 '17 at 00:00
  • @WindyFields - I meant even though &ref variable != &referent internally but to the programmer &ref variable == &referent to comply with the standard. – Amit Rastogi Aug 23 '17 at 06:28
  • @ar2015 - please check https://isocpp.org/wiki/faq/references and https://stackoverflow.com/questions/29322688/does-reference-variable-occupy-memory – Amit Rastogi Aug 23 '17 at 06:34