c++理解在清理后访问全局变量不会产生某种错误



我有一个关于全局变量在c++中如何工作的问题。我知道全局变量是邪恶的,所以这不是这个问题的重点。我只是想更深入地了解下面的例子中发生了什么

#include <cstdint>
#include <iostream>
#include <vector>
class B
{
public:
B();
~B();
private:
static std::vector<int32_t> v_;
};
B::B()
{
std::cout << "v_.size() = " << v_.size() << std::endl;
for (auto i : v_)
std::cout << i << std::endl;
}
B::~B()
{
std::cout << "v_.size() = " << v_.size() << std::endl;
std::cout << "v_[0] = " << v_[0] << std::endl;
std::cout << "v_.at(0) = " << v_.at(0) << std::endl;
for (auto i : v_)
std::cout << i << std::endl;
}
B b;
std::vector<int32_t> B::v_ { 5, -7 };
int main()
{
return 0;
}

给出以下输出:

$ ./test 
v_.size() = 0
v_.size() = 2
v_[0] = 0
v_.at(0) = 0
0
0

为什么B的析构函数中向量的大小仍然是2?

当我访问向量的元素时,我会得到随机内存,我有点理解,因为向量在B之前就被清理了。但对我来说,向量的大小应该是0,或者在询问大小时会抛出一些错误。即使使用at((函数,它也不会抛出错误,因为大小仍然是2。

我也知道我可以通过切换b和向量的初始化来解决这个问题。我的问题更多的是,为什么这个特定的例子没有出现某种错误,因为在我看来应该是这样。

注意:就像我的评论一样:为什么这个行为属于未定义的行为,而不是读取或写入非法的内存位置,因为向量在那一点上不存在?我有点认为这会/应该产生seg故障,我不明白为什么它没有

未定义的行为意味着程序的行为不是由C++标准定义的。一个合格的C++编译器可以用一个程序做任何事情,该程序已经或将表现出未定义的行为(是的,UB可以时间旅行(。

B::B中构造程序之前,通过将v_作为对象进行访问,程序显示出未定义的行为。既然它做到了这一点,那么程序执行的任何内容都不受C++标准的指定或约束。

在这种情况下,编译器将UB访问视为访问一个空的std::vector。这是有效的,因为任何东西都是有效的。然后程序继续进行,就好像你没有做UB(除了上述症状(,这也是一个有效的选择。

如果我们想象删除ctor中的UB,在销毁过程中,您的程序再次显示UB。这一次是通过在v_被销毁后将其作为vector对象进行访问。同样,通过这样做,程序的行为不受C++标准的定义或约束,无论是在UB之前、处还是之后。

在这种情况下,它的行为就像您有一个值为0的2个值的向量。这是一致的,因为任何东西都是一致的

许多可能性之一是,数据在堆上被回收,但指针仍处于悬空状态。将向量的"腐烂"数据视为指针,它们仍然指向2个sizeof(int).size()将其读取为2。然而,所指向的数据已在堆上回收,并且存在不同的数据。

最新更新