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?