Кто здесь прав? g или Visual Studio 2017?

#c #reference #visual-studio-2017 #g #undefined-behavior

#c #ссылка #visual-studio-2017 #g #неопределенное поведение

Вопрос:

Недавно я наткнулся на забавную «особенность». Приведенный ниже код одинаково компилируется как на g , так и на Visual Studio 2017.

 #include <iostream>
#include <list>

int main()
{
    std::list<int *> l;
    int a = 1, b = 2;
    l.emplace_back(amp;a);
    auto p = l.front();
    std::cout << p << 'n'; // prints x
    l.erase(l.begin());
    l.emplace_back(amp;b);
    std::cout << p << 'n'; // prints x
    std::cin.get();
}
  

Однако, если вы измените строку

 auto p = l.front();
  

Для

 auto amp; p = l.front();
  

Visual Studio по-прежнему выдает тот же результат (конечно, учитывая, что адрес x может измениться). Однако теперь g выдает мне результат

 x
x 4
  

Очевидно, что при передаче указателя по ссылке g распознает, что первый элемент списка теперь имеет другое значение, которое является другим адресом стека (смещение 4 по сравнению с исходным), в то время как Visual Studio 2017 этого не делает. Итак … кто сломался?

Ответ №1:

кто сломался?

Оба верны, потому что ваш код имеет неопределенное поведение.

После auto amp; p = l.front(); того, как вы удалили элемент из list , он p становится зависшим; любое разыменование на нем приводит к UB, означает, что возможно все.

Ссылки и итераторы на удаленные элементы недействительны.

Ответ №2:

После того, как l.erase(l.begin()); ссылка на первый элемент, ранее полученный в auto amp; p = l.front(); , становится недействительной, а доступ к значению, хранящемуся в p, приводит к неопределенному поведению. Итак, это ваш код, который поврежден.