Класс, имитирующий «указатель на ссылку», может сохранить вне области видимости переменные? - PullRequest
1 голос
/ 16 июля 2011

Я подумал о странном чите в C ++.Обычно я не могу вывести ссылку из области видимости, потому что не могу определить неинициализированную ссылку в содержащей области.Однако я могу определить указатель на класс, содержащий ссылку, не инициализировать его, а затем назначить ему адрес некоторой динамической памяти, инициализированной локальной переменной.Даже если этот динамический объект содержит ссылку на переменную, которая должна выйти из области видимости, указанный объект все еще имеет действительную ссылку с тем же значением!G ++ не жалуется, даже если я говорю, что это -pedantic, поэтому я предполагаю, что это действительно.Но как и почему?

struct int_ref
{
  int &x;
  int_ref(int &i): x(i) {}
};

#include <iostream>
using namespace std;

int main(void)
{
  int_ref *irp;
  int i = 1;
  int_ref a(i); // Creates an int_ref initialized to i
  irp = &a; // irp is now a pointer to a reference!
  // Prints 1
  cout << "irp->x = " << irp->x << " (i = " << i << ")" << endl;
  i = 2;
  // Prints 2
  cout << "irp->x = " << irp->x << " (i = " << i << ")" << endl;
  int j = 3;
  int_ref b(j);
  irp = &b;
  // Prints 3
  cout << "irp->x = " << irp->x << " (i = " << i << ", j = " << j << ")" << endl;
  i = 1;
  // Still prints 3
  cout << "irp->x = " << irp->x << " (i = " << i << ", j = " << j << ")" << endl;
  {
    int k = 4;
    irp = new int_ref(k);
    // k goes out of scope
  }
  int k = 1; // Doesn't affect the other k, of course
  // Prints 4 ?!
  cout << "irp->x = " << irp->x << " (i = " << i << ", j = " << j << ")" << endl;
}

Редактировать: На самом деле это может быть (как предлагается в ответах) недиагностированная висячая ссылка.Как насчет того, чтобы определить int_ref следующим образом:

struct int_ref
{
  const int &x;
  int_ref(const int &i): x(i) {}
};

Ссылка const не обязательно должна ссылаться на lvalue, поэтому не существует четко определенного понятия висячей.Код все еще не определен?

Ответы [ 2 ]

4 голосов
/ 16 июля 2011

То, что вы сделали, имеет неопределенное поведение .

  {
    int k = 4;
    irp = new int_ref(k);
    // k goes out of scope
  }
  int k = 1; // Doesn't affect the other k, of course
  // Prints 4 ?! ***it could print 42 - no guarantees***
  cout << "irp->x = " << irp->x << " (i = " << i << ", j = " << j << ")" << endl;

Вы сохраняете (и используете) ссылку на объект, который вышел из области видимости.Это неопределенное поведение независимо от того, насколько косвенно вы сохраняете эту ссылку.

Кажется, что худшее проявление неопределенного поведения работает нормально.В этом случае у вас ложное чувство безопасности, но носовые демоны могут летать повсюду, поверьте мне;)

Относительно того, почему компилятор не жалуется даже в педантичном режиме, ну, это очень сложносделать такой статический анализ кода, чтобы обнаружить такие вещи.Так что это оставлено для вашего собственного внимания.

3 голосов
/ 16 июля 2011

Тот факт, что ваш компилятор не выдает диагностику для вашей программы, не означает, что ваша программа хороша, допустима и безопасна.

Ваша последняя строка вызывает неопределенное поведение, потому что у вас есть свисающая ссылка.Это не должно быть диагностировано компилятором, но это также не делает это правильным.Вы можете получить 4 ( просто так случается, что все еще будет в этом месте в памяти), вы можете получить другое значение, вы можете получить ошибку сегментации, или ваш компьютер может взорваться.

Только не делайте этого.


Примечание по терминологии: здесь нет "указателя на ссылку" (такого не существует), только указатель наint_ref.

...