1

Consider

#include <iostream>

struct Foo
{
    int* n;
    Foo(){n = new int{};}
    ~Foo(){delete n;}
    int& get()
    {
        int* m = n;
        return *m;
    } 
};

int main()
{
    Foo f;
    std::cout << f.get();
}

This is a cut-down version of a class that manages a pointer, and has a method that returns a reference to the dereferenced pointer.

Is that defined behaviour?

P45 Imminent
  • 8,319
  • 4
  • 35
  • 78
  • 1
    Yes, why wouldn't it be? Make sure you obey the rule of three though https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three – Alan Birtles Aug 31 '22 at 07:10
  • 1
    Yes, it fine, and it's fine to use the reference until the point that `n` is deleted. – john Aug 31 '22 at 07:10
  • 2
    `int& get() { return *n; } ` is a simpler way to write the same function. No need for an extra variable. – john Aug 31 '22 at 07:11
  • 1
    In the shown example, `m` point to the same location as `n`. Returning `*m` or `*n` means the same thing. As long as the life-time of the integer that `n` (and `m`) is pointing to outlives the use of the reference, that's all good and fine and well-behaved. – Some programmer dude Aug 31 '22 at 07:11
  • The larger issue (IMO) is why you want a pointer to a single value in the first place. And why do you want it as a raw non-owning pointer with manual and explicit memory handling and not following the rules of three or five, instead of a smart pointer like `std::unique_ptr`? – Some programmer dude Aug 31 '22 at 07:12
  • @john: Yes I probably can simplify it further. I think the problem I have is that I don't really understand what references refer to. My boss says they refer to the original `int` in this case, not the pointer in a dereferenced form. – P45 Imminent Aug 31 '22 at 07:13
  • @Someprogrammerdude: It's a cut down version. Real code has a C++ container with some reference counting in a C like structure for an ABI. – P45 Imminent Aug 31 '22 at 07:14
  • 3
    To maybe clear things up, you return a reference to what the pointer is pointing to. – Some programmer dude Aug 31 '22 at 07:15
  • @Someprogrammerdude: That's nicely put. Better than my boss did. – P45 Imminent Aug 31 '22 at 07:15
  • @P45Imminent: From a language implementer's point of view, references are aliases. That means they do not actually have a on-metal counterpart, like pointers do (where a language level pointer eventually is bijectively mapping to an address). Depending on circumstances on the machine level a reference might be implemented using the same mechanisms like pointers, or just as valid by location substitution during register assignment. – datenwolf Aug 31 '22 at 07:16
  • Whenever you have problems with pointers, I suggest using pen and paper to draw everything up. For your case with `n` and `m`, draw three boxes. Label one `n`, another `m` and the third with an example integer value. Draw arrows from the `n` and `m` boxes to the value box. When dereferencing a pointer you go to the box containing the pointer (`n` or `m` in your example) and follow the arrow to the value. It could help you visualize what's happening. Sure, in this example case that might be trivial, but it's a good tip (I hope) for more complex cases. – Some programmer dude Aug 31 '22 at 07:19
  • They aren't, but its easiest to think of a reference as basically a pointer that can't be null – Alan Birtles Aug 31 '22 at 07:19
  • @P45Imminent Also, note that [just returning a reference to a local variable is not undefined behavior in itself](https://stackoverflow.com/questions/71693551/is-returning-a-reference-to-a-local-int-variable-always-undefined-behavior). It's just that if you were to use that returned reference then you'll get UB. Also, note that in your example, the dynamically allocated `int` still exists so even if you were to use that returned reference, the program will still be well-formed. – Jason Aug 31 '22 at 07:22
  • Pedantically: This code doesn't return a reference to a pointer. It returns a reference to an `int`. It does so by dereferencing a pointer. A "reference to a pointer" would be something like `int*& get_pointer() { return n; }` – Nathan Pierson Aug 31 '22 at 13:37

1 Answers1

7

Is that defined behaviour?

Yes, the given program is well-formed. You're returning a non-const lvalue reference that refers to a dynamically allocated integer pointed by the pointer n and m. The integer object still exists after the call f.get(). That is, itis not a function local variable.


Note also that just returning a reference to a potentially local variable is not undefined behavior in itself. It's just that if you were to use that returned reference(aka dangling reference) to a local variable that nolonger exists, then we will get UB.

Jason
  • 36,170
  • 5
  • 26
  • 60