25

Does a reference have a storage location or is it just an alias for another location? Does this differ by C++ revision or is it consistent with all versions of C++? And if a reference has a storage location, does it then just allow value semantics on a pointer like type?

How would a reference work when you use it as such:

struct aStruct{
   int aVariable;
   aClass& aReferencetoaClass;
};

Does it take up space or is it an alias?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Tarick Welling
  • 3,119
  • 3
  • 19
  • 44

2 Answers2

18

The latest C++20 spec(§ 9.2.3.3) and at least since the C++ 2005 draft spec state:

It is unspecified whether or not a reference requires storage

The actual implementation is on a case-by-case basis. Obviously if a class has a single member variable that is a reference that will need to be stored somewhere. But the compiler has leeway when to use a reference solely as an alias, as you put it.

Tarick Welling
  • 3,119
  • 3
  • 19
  • 44
Paul Evans
  • 27,315
  • 3
  • 37
  • 54
  • Well, yes - it depends on the context. In a struct, you'd have to have the reference require storage, otherwise how would you manage different struct instances? In a block of code, where you create a temporary reference, it could just be an alias. I think the point of not specifying it is exactly for the compiler to be able to pick. – Jens Finkhaeuser Jul 01 '19 at 13:33
  • 1
    If an object is available at an ABI boundary, it needs to follow the ABI. – curiousguy Jul 01 '19 at 18:58
12

Most compilers, for any C++ standard up to C++17 at least, will effectively implement a reference as a pointer, unless optimized out.

In particular, inside an struct, it will take take up the size of a pointer (plus alignment/padding etc.).

Therefore, this will hold in most environments:

struct S {
    char & a;
};

static_assert(sizeof(S) == sizeof(void *));
Acorn
  • 24,970
  • 5
  • 40
  • 69
  • 4
    "In particular, inside an struct" - disagree, it may refer to another member of the same struct, then it could be just an alias. – Slava Jul 01 '19 at 13:39
  • @Slava How? All data members need to have a unique address (until we get `[[no_unique_address]]` in C++20). – Acorn Jul 01 '19 at 13:42
  • 4
    @Acorn it's unspecified if references have storage, so it's unspecified if they have an address. – Caleth Jul 01 '19 at 13:46
  • @Slava The sizes of all types must be known at compile time. The referred objects are determined at runtime. How could the compiler possibly know that members of all instances of an object refer to another member? I don't think that's practically possible - even though standard might not explicitly deny it. – eerorika Jul 01 '19 at 14:22
  • @Caleth Hm... In cppreference it claims it is implementation-defined. I am not sure I am reading [intro.object]p8 correctly: "Otherwise, the circumstances under which the object has zero size are implementation-defined", but I guess it refers to that. – Acorn Jul 01 '19 at 14:28
  • @eerorika "How could the compiler possibly know that members of all instances of an object refer to another member?" how about `struct foo { int i; int &ri = i; };` ? – Slava Jul 01 '19 at 14:35
  • 2
    @eerorika Indeed. I guess one can come up with a edge case where it can be proved that a type has a reference member that always points to a known place so it can optimize it out -- but I doubt a compiler will care to optimize for that, given it is basically useless in real code. – Acorn Jul 01 '19 at 14:37
  • @Slava and then you write `foo f; foo ff{f};` and suddenly you have `ff.ri` which does not refer to another member. And there is no way for compiler to know whether this will be done in some another translation unit that hasn't yet been compiled. – eerorika Jul 01 '19 at 14:37
  • @eerorika I can prohibit copy. – Slava Jul 01 '19 at 14:38
  • @Slava Yes, and you can even use it as a local type inside a function to avoid having to care about other TUs. I tried that quickly in several compilers (plus putting it inside an anonymous namespace etc.), and they do not seem to not optimize the member away no matter what. Anyway, my answer was written concerning all major compilers, not as a legalese answer. – Acorn Jul 01 '19 at 14:43
  • @Acorn a reference isn't an object – Caleth Jul 01 '19 at 14:55
  • @Caleth D'oh! Thanks a lot. Then I don't know where cppreference is taking that from (if at all correct). – Acorn Jul 01 '19 at 16:32
  • 3
    @Slava: Yes, in theory a C++ implementation could do that. In practice I'm not aware of any that do optimize away references that can be proven to always be initialized to refer to a known location (another member of the struct/class, or always to the same static object). So in practice references are basically syntactic sugar around `char *const c;`. To do otherwise, the struct layout would depend on compile-time proof about how the reference is initialized. That potentially depends on whether you compile with optimization or not, and not being able to link release+debug objects = weird. – Peter Cordes Jul 02 '19 at 02:02