谁在这里? g++ 还是 Visual Studio 2017?
Who's right here? g++ or Visual Studio 2017?
最近看到一个有趣的"feature"。
下面的代码在 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年没有。那么...谁坏了?
在 l.erase(l.begin());
之后,对先前在 auto & p = l.front();
获得的第一项的引用变得无效,并且访问存储在 p 中的值会导致未定义的行为。所以是你的代码坏了。
who's broken?
两者都是正确的,因为您的代码有未定义的行为。
在 auto & p = l.front();
之后,你 erased 来自 list
的元素,然后 p
变成悬挂;对它的任何取消引用都会导致 UB,意味着一切皆有可能。
References and iterators to the erased elements are invalidated.
最近看到一个有趣的"feature"。 下面的代码在 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年没有。那么...谁坏了?
在 l.erase(l.begin());
之后,对先前在 auto & p = l.front();
获得的第一项的引用变得无效,并且访问存储在 p 中的值会导致未定义的行为。所以是你的代码坏了。
who's broken?
两者都是正确的,因为您的代码有未定义的行为。
在 auto & p = l.front();
之后,你 erased 来自 list
的元素,然后 p
变成悬挂;对它的任何取消引用都会导致 UB,意味着一切皆有可能。
References and iterators to the erased elements are invalidated.