我有一个关于全局变量如何在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的析构函数中 vector 的大小仍为2?
当我访问 vector 的元素时,我得到了随机内存,这是我理解的,因为 vector 在B之前被清理了。但是对我来说, vector 的大小应该为0甚至更好,在请求时抛出某种错误尺寸。即使使用at()函数也不会引发错误,因为大小仍然为2。
我也知道我可以通过切换b和 vector 的初始化来解决此问题。我的问题更多是为什么这个特定的示例不会引发某种错误,而我认为应该如此。
注意:就像我的评论一样,为什么此行为属于未定义行为,而不是因为该点不存在 vector 而读取或写入非法的内存位置?我当时以为这会/应该产生段错误,但我不明白为什么它不会
最佳答案
未定义行为表示C++标准未定义程序的行为。合格的C++编译器可以使用具有此功能的程序对进行任何操作,或者将表现出未定义的行为(是的,UB可以进行时间旅行)。
在v_
中构造程序之前,通过将B::B
作为对象访问,您的程序表现出未定义的行为。既然这样做,C++标准就不会指定或限制程序执行。
在这种情况下,编译器将UB访问视为正在访问空std::vector
。这是有效的,因为任何东西都是有效的。如果您没有完成UB(上述症状除外),该程序将继续进行,这也是有效的选择。
如果我们设想移除ctr中的UB,则在销毁过程中,您的程序将再次显示UB。这次通过销毁v_
作为vector
对象来访问它。同样,通过此操作,在UB之前,之后和之后,程序的行为不受C++标准的定义或约束。
在这种情况下,它的行为就好像您有一个2个值的 vector ,其值均为0。这是符合的,因为符合。
许多可能性之一是数据在堆上被回收,但是指针悬空了。将 vector 的“旋转”数据视为指针时,它们仍将2 sizeof(int)
分开,而.size()
则将其指向2。但是,指向的数据已在堆上回收,并且那里有不同的数据。
关于c++ - C++理解清除后访问全局变量不会产生某种错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53745137/