最近,我遇到了一个有趣的“功能”。 下面的代码在g ++和Visual Studio 2017上均能编译。
#include <iostream>
#include <list>
int main()
{
std::list<int *> l;
int a = 1, b = 2;
l.emplace_back(&a);
auto p = l.front();
std::cout << p << '\n'; // prints x
l.erase(l.begin());
l.emplace_back(&b);
std::cout << p << '\n'; // prints x
std::cin.get();
}
但是,如果您换行
auto p = l.front();
到
auto & p = l.front();
Visual Studio仍然提供相同的输出(当然,考虑到地址x可能会改变)。但是,现在g ++给了我输出
x
x+4
很明显,当通过引用传递指针时,g ++会认识到列表的第一个元素现在具有不同的值,这是堆栈的不同地址(与初始地址相比偏移量+ 4),而Visual Studio 2017没有。所以...谁伤了?
答案 0 :(得分:5)
谁坏了?
这都是正确的,因为您的代码具有未定义的行为。
在auto & p = l.front();
之后,您erased list
中的元素,然后p
变成了悬空;任何对其的取消引用都将导致UB,这意味着一切皆有可能。
对已删除元素的引用和迭代器无效。
答案 1 :(得分:4)
在$ bundle init
Writing new Gemfile to /private/var/folders/_2/rg7rz1h56sb2ln5f75gjr7558b1wz3/T/tmp.PPIvZRXi/Gemfile
$ echo "gem 'ohai'" >> Gemfile
$ bundle install --path vendor/gems --jobs 4
...
之后,对先前在l.erase(l.begin());
获得的第一项的引用变得无效,并且访问存储在p中的值将导致未定义行为。所以是您的代码被破坏了。