Кто-нибудь может сказать мне, безопасно ли это, потому что я думаю, что это не так:
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)
}
Я понимаю, почему (1) работает. Мы передаем указатель, функция принимает его как ссылку.
Но почему не работает (2)? С моей точки зрения, мы передаем один и тот же указатель, просто не присваивая его сначала переменной-указателю. Я предполагаю, что &i
является rvalue и не имеет собственной памяти, поэтому ссылка не может быть действительной. Я могу согласиться с этим объяснением (если это правда).
Но какого черта компилирует (3)? Разве это не означает, что мы разрешаем недопустимую ссылку, поэтому b.m_i
по существу не определено?
Я совершенно не прав в том, как это работает? Я спрашиваю, потому что получаю странный сбой модульного теста, который я могу объяснить только тем, что указатели становятся недействительными. Они случаются только с некоторыми компиляторами, поэтому я предполагал, что это должно быть что-то за пределами стандарта. ничего не подозревающий вызывающий абонент всегда может вызвать его с помощью &i
, как с обычным аргументом указателя?
Дополнение: Как отметил @ franji1, следующая интересная мысль поможет понять, что здесь происходит. Я модифицировал main (), чтобы изменить внутренний указатель, а затем распечатать члены 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
}
Итак, очевидно, что a1 работает так, как задумано. Однако, поскольку b не может знать, что j был изменен, кажется, что он содержит ссылку на «личный» указатель, но меня беспокоит то, что он не определен в стандарте должным образом, поэтому могут быть компиляторы, для которых этот «личный» указатель не определен. Кто-нибудь может это подтвердить?