Can someone tell me if this is safe, because I think it isn't:
class A { public: A(int*& i) : m_i(i) {} int*& m_i; }; class B { public: B(int* const& i) : m_i(i) {} int* const & m_i; }; int main() { int i = 1; int *j = &i; A a1(j); // this works (1) A a2(&i); // compiler error (2) B b(&i); // this works again (3) } I understand why (1) works. We are passing a pointer, the function accepts it as a reference.
But why doesn't (2) work? From my perspective, we are passing the same pointer, just without assigning it to a pointer variable first. My guess is that &i is an rvalue and has no memory of its own, so the reference cannot be valid. I can accept that explanation (if it's true).
But why the heck does (3) compile? Wouldn't that mean that we allow the invalid reference so b.m_i is essentially undefined?
Am I completely wrong in how this works? I am asking because I am getting weird unit test fails that I can only explain by pointers becoming invalid. They only happen for some compilers, so I was assuming this must be something outside the standard.
So my core question basically is: Is using int* const & in a function argument inherently dangerous and should be avoided, since an unsuspecting caller might always call it with &i like with a regular pointer argument?
Addendum: As @franji1 pointed out, the following is an interesting thought to understand what happens here. I modified main() to change the inner pointer and then print the members m_i:
int main() { int i = 1; int *j = &i; // j points to 1 A a1(j); B b(&i); int re = 2; j = &re; // j now points to 2 std::cout << *a1.m_i << "\n"; // output: 2 std::cout << *b.m_i << "\n"; // output: 1 } So, clearly a1 works as intended. However, since b cannot know that j has been modified, it seems to hold a reference to a "personal" pointer, but my worry is that it is not well defined in the standard, so there might be compilers for which this "personal" pointer is undefined. Can anyone confirm this?
&iis not a valid reference to int*, but it is valid const reference to int*, that's all.