我在 main 的同一个文件中定义了一个类,在 2 个单独的文件中定义了另一个类(充满静态函数/成员),它崩溃了。我想这可能与全局/静态实例的生命周期有关。似乎在ctor中,静态成员还没有被初始化,而且可能会发生在退出时,静态成员在第一个实例被破坏之前被释放。 这是测试代码:
//testh.h
#include <map>
class Sc {
public:
static void insert();
static void out();
private:
static std::map<int, int> map_;
};
//testcpp.cpp
#include "testh.h"
#include <iostream>
std::map<int, int> Sc::map_;
void Sc::insert() {
map_.insert(std::make_pair(2,3));
}
void Sc::out() {
for(auto m : map_) {
std::cout << m.first << ' ' << m.second << '\n';
}
}
//main.cpp
#include "testh.h"
class Nc {
public:
Nc() {
Sc::insert();
Sc::out();
}
~Nc() {
Sc::insert();
Sc::out();
}
};
Nc nc;
int main() {
system("pause");
return 0;
}
下面是上面代码的一些奇怪行为:
如果我将 staic 成员替换为 int,它不会崩溃,所以我想 std::map 可能有问题?
如果我把所有的代码都放到main.cpp中,它不会崩溃,但是这些不会生成相同的代码吗?
如果我不想进行动态分配(新),如何解决这个问题?
最佳答案
问题是你不知道全局变量的构造顺序:
这个
// test.cpp
std::map<int, int> Sc::map_;
还有这个
//main.cpp
Nc nc;
因为它们在不同的编译单元中,所以标准不保证它们的创建顺序。因此如果nc
首先创建然后尝试使用 Sc::map_
将失败(并且 nc
确实通过其对静态的调用来使用它)。
当您将全局变量放入一个文件时:
//main.cpp
std::map<int, int> Sc::map_;
Nc nc;
那么顺序就有保障了。这是声明的顺序。所以只要你把Sc::map_
首先,一切都会起作用。
有一个简单的技术可以解决这个问题::
替换这个:
private:
static std::map<int, int> map_;
};
与:
private:
static std::map<int, int>& getMap()
{
static std::map<int, int> instance;
return instance;
}
};
但真正的问题是您使用的是全局可变状态(全局变量)。尽量不要使用它们。它将您的代码紧密绑定(bind)到全局状态。您应该将状态传递给带有参数的方法或通过知道如何检索状态的对象。
关于c++全局/堆栈实例ctor/dtor在调用静态函数时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15242290/