C++静态成员在Python扩展模块中的初始化
简短版本
我不太明白如何可靠地初始化Python扩展中的静态成员。特别是,如何确保来自不同编译单元的代码按照特定的加载顺序执行,以满足某些依赖关系?
详细版本
我有一些代码需要多次计算各种组合函数,比如阶乘、二项式等。为了提高效率,我只需要构建一个表格来存储这些值,然后在需要的时候查找它们。而且我需要一个简单的接口来获取这些值,所以我就创建了C++类,把这些表格作为静态成员。
举个简单的例子,计算阶乘时,我有以下代码。在 Combinatorics.hpp
文件中:
class FactorialFunctor {
private:
static const std::vector<double> FactorialTable;
public:
FactorialFunctor() { };
inline double operator()(const unsigned int i) const {
return FactorialTable[i];
}
};
在 Combinatorics.cpp
文件中:
const std::vector<double> FactorialFunctor::FactorialTable = FactorialTableCalculator();
这里的 FactorialTableCalculator
是一个本地函数,它只返回合适的向量。[那些 operator()
的实现对于二项式等会更复杂,所以我才使用类来封装这些东西。]
我使用SWIG将C++代码封装起来,并在Python中使用。之前一切都很顺利,直到我在一个新的集群上编译我的代码。现在我觉得之前的成功可能只是运气好。
当我在新集群上导入我的Python模块时,Python就崩溃了。Python甚至没有完成导入步骤。通过使用 gdb
,我发现问题出在代码的另一部分,它的初始化调用了一个 Factorial
函数对象。但此时 FactorialTable
还没有初始化,所以整个程序就崩溃了。
因此,我需要确保在其他代码计算之前先计算出阶乘。我在distutils中告诉它所需的顺序,但显然在这个集群上并不是按照这个顺序调用的。我需要在链接过程中注意什么阶段吗?
1 个回答
没有可靠的方法可以强制静态成员的初始化顺序。
不过,从代码来看,我觉得你需要的不是一个静态成员,而是一个单例模式。在C++中,单例模式通常是通过一些函数来实现的,像这样:
FactorialFunctorData& _FactorialFunctorData()
{
static FactorialFunctorData data_;
return data_;
}
这样一来,你就可以在执行时按需要的顺序调用这些函数,从而控制执行的顺序。