Почему это работает? Возврат константных ссылок в C ++ - PullRequest
1 голос
/ 07 февраля 2010

Я дурачусь с C ++ и константными ссылками и растерялся, почему этот код работает:

#include <iostream>

class A {
public:
    A() : a_(50) {}
    const int& getA() const { return a_; }
private:
    const int a_;
};

int main(int argc, char* argv[])
{
    A* a = new A();
    const int& var = a->getA();
    std::cout << var << std::endl;
    delete a;
    std::cout << var << std::endl;
}

Результат:

50
50

Вот мои мысли:

var хранит ссылку на _.
когда a удаляется, a_ также следует удалять.
при повторном обращении к var он больше не содержит действительной ссылки и должен произойти сбой сегментации.

Почему это работает? Я не верю, что я делаю временную копию.

Ответы [ 4 ]

13 голосов
/ 07 февраля 2010

В тот момент, когда вы удалили a, доступ к var стал вашей дверью в неопределенную область поведения.

Это "работает" случайно.Пространство, на которое ссылался var, больше не ваше, но на этот раз вам не удалось получить к нему доступ.Это могло привести к ошибке сегментации, возвращению числа, отличного от 50, или переформатированию вашего жесткого диска.

Помните, что кажущаяся работоспособность - это один из возможных способов проявления неопределенного поведения.

3 голосов
/ 07 февраля 2010

Удаление объекта не очищает память. Значение будет оставаться там до тех пор, пока память не будет использована для чего-то другого. Так что это может работать некоторое время ....

В некоторых реализациях C ++ есть «режим отладки», который устанавливает определенное значение для всей удаленной памяти, чтобы обнаруживать подобные ошибки.

2 голосов
/ 07 февраля 2010

Когда вы удаляете a, вы освобождаете память и позволяете последним новым перезаписывать ее.До этого момента все переменные внутри вашего удаленного объекта все еще находятся в памяти, но могут быть переопределены в любое время.

1 голос
/ 07 февраля 2010

Это довольно сложно из-за ключевого слова const.

Правда, в этом случае вы могли бы читать неинициализированную память. Несколько мыслей по этому поводу:

  1. Вы не используете режим отладки: это, как правило, не очень хорошая идея, если код не был протестирован, но он оставляет две опции:
    • Менеджер памяти режима освобождения не перезаписывает память, поэтому вы получаете доступ к последнему известному адресу, который все еще работает случайно
    • ИЛИ Вся операция полностью оптимизирована, поскольку компилятор знает, что вы не изменили значение и не могли измениться извне (хотя это может быть неверно из-за ограничений правильности констант в C ++)
  2. Вы находитесь в режиме отладки, но активированы оптимизации, поэтому применяется тот же аргумент
  3. Содержимое _a, поскольку помеченное const не распределяется ни в куче, ни в стеке, а находится в разделе DATA приложения, поэтому ссылка действительно может быть действительной, не только шанс. [РЕДАКТИРОВАТЬ]: Это может быть верно только для static const переменных.

Вы можете написать собственный менеджер памяти или исследовать поведение режима отладки вашего компилятора, потому что это очень, очень важно. Например, Visual Studio устанавливает переменные на 0xCDCDCDCD. Вы также найдете забавные значения, такие как 0xDEADC0DE в конце массивов.

...