2

I'm wondering if there's a memory cost to having multiple "constant reference" variables in the same scope pointing to the same object:

const Animal& animal = getAnimal();
const Dog& dog = static_cast<const Dog&>(animal);

Conceptually, animal and dog are two variables, each of pointer size, and thus would take up 2 registers (or a 2*pointer-size region on the stack).

But (assuming that there's no multiple inheritance etc.), the compiler could know that they both must hold the same pointer value throughout their lifetime.

So, can these two variables share a single register (or a single pointer-sized region on the stack)?
By "can", I mean:

  • Does the C++ standard allow it?
  • Would modern compilers do it?
smls
  • 5,738
  • 24
  • 29
  • 1
    "are two variables, each of pointer size" How do you know? I dont know any way to get the size of the reference itself – 463035818_is_not_an_ai Jul 03 '20 at 10:53
  • 4
    C++ has the 'as if' rule. Within certain constraints the compiler can do what ever it likes as long as the observable behaviour of the program is not changed. So certainly the C++ standard allows the compiler to share one location for the two references (or even to entirely eliminate both references). Whether a compiler would actually do this in practise probably depends on a lot of different factors. – john Jul 03 '20 at 10:53

2 Answers2

5

Does the C++ standard allow it?

Sure, why not. There is no way you could tell the difference. The so-called "as-if rule" allows compilers to do any optimization as long the observable behavior is the same as if it didn't do any optimizations (side note: there are exceptions, where optimizations are allowed to change observable behavior).

Conceptually, animal and dog are two variables, each of pointer size, ...

Nope. Conceptually, references are aliases. They need not take any space, because they are just a different name for the actual object. The C++ standard does not specify the size a reference takes or how it is implemented. sizeof a reference gives you the size of the refered to object. The address of a reference is the address of the referd to object. I am not aware of any way to tell the difference if a reference is implemented as pointer or in any other way (and I strongly doubt that there is a portable way).

Would modern compilers do it?

To answer this I suggest you to take some real code and look at the compilers output. This is a nice tool to help with that: https://godbolt.org/.

PS: I sense a small misunderstanding. In fact the const in your example is not that relevant. Having a const reference does not imply that the value will not change. It only means that you are not allowed to change the value through that reference. Maybe best exaplained by a small example:

struct foo {
    const int& ref;
};

int main() {
    int x = 1;
    foo f{x};
    x = 42;
}    

Here f holds a const reference to x. That doesn't mean that x will never get modified. It only means that f cannot modify x via ref. This is especially important in a multithreaded environment, where assuming that an object is const just because you have a const reference will cause trouble.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • 1
    Is it really incorrect to say that references are conceptually equivalent to pointers, except for the things they cannot do? (e.g. you cannot measure the address or size of a reference) – user253751 Jul 03 '20 at 11:16
  • Actually you can measure the size of a reference: `sizeof(struct foo)` in your last example – user253751 Jul 03 '20 at 11:17
  • @user253751 "conceptually" one can use analogies, but I never saw anything good coming out from saying references are like pointers, rather many misunderstandings are based on that – 463035818_is_not_an_ai Jul 03 '20 at 11:17
  • @user253751 how do you tell the difference between padding and the sizeof the member? The sizeof a type is not the sum of sizeof its members. Also, whatever you measure, next time it could be different – 463035818_is_not_an_ai Jul 03 '20 at 11:18
  • What would you say about `std::has_unique_object_representations_v`? – Evg Jul 03 '20 at 11:28
  • @Evg returns `false` for me: https://godbolt.org/z/GSj8C4 – 463035818_is_not_an_ai Jul 03 '20 at 11:31
  • Yeah, I tested that. But why? `sizeof(foo)` is `8`, `std::is_trivially_copyable_v` returns `true`. – Evg Jul 03 '20 at 11:32
  • @Evg `S`? I can only guess. What does it mean for refrenes to have eqaul value? I could imagine that `f{x}` and `f{y}` can be considered to have the same value but refer to different `int`s. Interesting question.... – 463035818_is_not_an_ai Jul 03 '20 at 11:34
  • Sorry, `S` is just `foo`. – Evg Jul 03 '20 at 11:34
  • @Evg with clang has unique representation: https://godbolt.org/z/8oj8sQ – 463035818_is_not_an_ai Jul 03 '20 at 11:37
  • Posted a [question](https://stackoverflow.com/questions/62714864/does-a-struct-with-a-reference-have-unique-object-representation). – Evg Jul 03 '20 at 11:53
3

Can multiple 'const reference' variables share the same memory?

Sure, variables can sometimes share memory. In some cases, neither variable might use any memory.

This applies to all trivial types.

Conceptually, animal and dog are two variables, each of pointer size

Conceptually, the standard doesn't specify the size of references. In practice though, if a reference variable needs storage, then it will be the size of a pointer indeed.

Does the C++ standard allow it?

Yes.

Would modern compilers do it?

Depends on context. There are cases where they would, and cases where they practically can't.

eerorika
  • 232,697
  • 12
  • 197
  • 326