Ссылка на временную переменную - почему компилятор не обнаруживает ее? - PullRequest
3 голосов
/ 21 сентября 2011

Надеюсь, это не дубликат, я прочитал ряд связанных вопросов, но никто, похоже, не охватил этот случай:

 #include <iostream>

int* return_dangling_p()
{
        int x = 1;
        return &x;  // warning: address of local variable 'x' returned
}

void some_func()
{
    int x = 2;
}

int main(int argc, char** argv)
{
    //  UB 1
    int* p = return_dangling_p();
    std::cout << *p;               // 1
    some_func();
    std::cout << *p;               // 2, some_func() wrote over the memory

    // UB 2
    if (true) {
        int x = 3;
        p = &x;     // why does compiler not warn about this?
    }
    std::cout << *p;    // 3
    if (true) {
        int x = 4;    
    }
    std::cout << *p;    // 3, why not 4?

    return 0;
}

Я думал, что это два случая одного и того же неопределенного поведения.Вывод равен 1233, а я (наивно?) Ожидал 1234.

Так что мой вопрос: почему компилятор не жалуется во втором случае и почему стек не переписывается, как в случае12?Я что-то упустил?

(MinGW 4.5.2, -Wall -Wextra -pedantic)

РЕДАКТИРОВАТЬ: я знаю, что обсуждать результаты UB бессмысленно.Моя главная проблема заключалась в том, есть ли какая-либо более глубокая причина, по которой один обнаруживается компилятором, а другой нет.

Ответы [ 2 ]

3 голосов
/ 21 сентября 2011

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

Вы не можете сделать ничего полезного в отношении поведения, которое вы наблюдаете, когда вызываете неопределенное поведение. Конечный результат мог быть 3, это могло быть 4, или это могло быть что-то еще.

[Если вам нужно объяснение, я предлагаю взглянуть на ассемблер, созданный компилятором. Если бы мне пришлось угадывать, я бы сказал, что компилятор полностью оптимизировал окончательный if (true) { ... }.]

3 голосов
/ 21 сентября 2011

почему компилятор не жалуется во втором случае

Я не уверен. Я полагаю, что мог.

почему память не перезаписывается как в случае 12

Это неопределенное поведение. Все может случиться.

Продолжайте читать, если вы действительно любопытны ...

Когда я компилирую ваш код как есть, мой компилятор (g++ 4.4.3) помещает две x переменные в UB 2 в разные места в стеке (я проверил это, посмотрев разборку). Поэтому они не конфликтуют, и ваш код также выводит 1233 здесь.

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

if (true) {
    int x = 4;    // 3, why not 4?
    &x;
}

Вот что происходит, когда я компилирую без каких-либо опций оптимизации. Я не экспериментировал с оптимизацией (в вашей версии кода нет причин, по которым int x = 4 нельзя полностью оптимизировать).

чудеса неопределенного поведения ...

...