C++ 部分初始化其他模块中定义的变量
我正在考虑一个特定的解决方案,其中我想初始化在其他模块中定义的数组的一个单元(将有许多模块初始化一个表)。在运行main之前不会读取数组(因此静态初始化顺序没有问题) 我的做法:C++ 部分初始化其他模块中定义的变量,c++,optimization,compiler-construction,static,initialization,C++,Optimization,Compiler Construction,Static,Initialization,我正在考虑一个特定的解决方案,其中我想初始化在其他模块中定义的数组的一个单元(将有许多模块初始化一个表)。在运行main之前不会读取数组(因此静态初始化顺序没有问题) 我的做法: /* secondary module */ extern int i[10]; // the array const struct Initialize { Initialize() { i[0] = 12345; } } init; /*主模块*/ #包括 int i[10]; int main(
/* secondary module */
extern int i[10]; // the array
const struct Initialize {
Initialize() { i[0] = 12345; }
} init;
/*主模块*/
#包括
int i[10];
int main()
{
printf(“%d\n”,i[0]);//检查该值是否已初始化
}
编译器不会去掉init
常量,因为构造函数有副作用。我说得对吗?机械装置可以吗?在GCC(-O3)上,一切正常
//编辑在现实世界中,将有许多模块我希望避免额外的模块,这是一个集中所有次要初始化例程的中心位置(为了更好的可扩展性)。因此,每个模块触发自己的初始化非常重要。编辑
/*secondary module (secondary.cpp) */
int i[10];
void func()
{
i[0]=1;
}
/*主模块(main.cpp)*/
#包括
外部内部i[];
void func();
int main()
{
func();
std::cout我认为您不希望在主模块adf88中使用extern int I[10];
。这可能会起作用,但很危险。单个模块中的全局/静态构造顺序是未定义的,模块加载顺序也是未定义的(除非您明确管理它)。例如,您假设在secondary.c Initialize()ctor运行期间,i已经存在。您必须非常小心,不要让两个模块初始化相同的公共数据,或者让两个模块执行初始化时产生重叠的副作用
我认为解决这种需求的更简洁的设计是让公共数据的所有者(您的主模块)将其作为全局单例公开,并提供一个接口来执行所需的任何数据初始化。您将有一个中心位置来控制初始化顺序,甚至可能控制并发访问(使用关键部分或其他并发原语)-
/主模块(main.c)/
#包括
公共类
{
int i
public:
const int GetI() { return i;}
void SetI(int newI) { i = newI; }
void incI()
{
AcquireSomeLock();
i++;
ReleaseTheLock();
}
}
CommonDat g_CommonDat;
CommonDat* getCommonDat() { return &g_CommonDat; }
int main(void)
{
printf("%d",getCommonDat()->GetI());
}
最好让辅助模块在运行时的受控时间(而不是在全局c'tors过程中)调用这些接口
(注:您将文件命名为C文件,但将问题标记为C++。当然,建议代码是C++)。
< P>这是用MSVC编译器进行的,但是GNU C++不适用(至少对我来说)。GNU链接器会删除所有未在编译单元外使用的符号。我知道只有一种方法可以保证初始化:“init一”。成语。例如:
init_once.h:
template <typename T>
class InitOnce
{
T *instance;
static unsigned refs;
public:
InitOnce() {
if (!refs++) {
instance = new T();
}
}
~InitOnce() {
if (!--refs) {
delete instance;
}
}
};
template <typename T> unsigned InitOnce<T>::refs(0);
我可以问一下,当您可以使用std::vector
时,为什么要使用数组(有越界的风险)
std::vector<int>& globalArray()
{
static std::vector<int> V;
return V;
}
bool const push_back(std::vector<int>& vec, int v)
{
vec.push_back(v);
return true; // dummy return for static init
}
这似乎更简单,也不容易出错。但在C++0x之前,它是不兼容多线程的。有一点很重要-您没有注意到我想要初始化表的单元格。我编辑了我的示例,以便它现在在代码中可见。我也编辑了我的帖子-我更好地解释了写“在模块内初始化”时我想说的话。您仍然假设在每个模块初始化期间,i[]阵列已经分配(未初始化)。当应用程序启动时,AFAIK静态存储空间在一个步骤中分配(并归零)。启动:这是关于全局静态存储空间什么是“模块”?转换单元?共享库?静态库?如我所写“在运行main之前不会读取数组"因此,初始化顺序没有问题。我不希望在中心位置进行初始化。我希望每个次要初始化都从关联的模块触发。这不仅仅是初始化顺序问题-您能否保证在辅助模块初始化期间甚至分配阵列?在单个翻译单元根据3.6.2定义得很好。我不确定您称之为“模块”的是什么——因此,这可能只是对它在更精细粒度级别上的表现的评论(假设为“模块”>translation unit)我将OP中的“module”解释为二进制,比如windows中的dll。是否定义了依赖dll加载的顺序?这实际上是一个诚实的问题-可能存在这样一个我不知道的规范。哦,我看到OP评论说他指的是翻译单元。因此init顺序的关注点确实是不相关的。接受。那么我尝试做的是不可能。必须从单元外部以某种方式引用初始值设定项。如果没有这种风险,则意味着您的模块已经紧密耦合(即他们需要知道写入哪个索引)在这种情况下,你最好把它写在一个源文件中,这样你就可以一目了然地检查索引是否正确。我的观点是关于解耦的。
template <typename T>
class InitOnce
{
T *instance;
static unsigned refs;
public:
InitOnce() {
if (!refs++) {
instance = new T();
}
}
~InitOnce() {
if (!--refs) {
delete instance;
}
}
};
template <typename T> unsigned InitOnce<T>::refs(0);
#include "init_once.h"
class Init : public InitOnce<Init>
{
public:
Init();
~Init();
};
static Init module_init_;
#include "unit.h"
extern int i[10]; // the array
Init::Init()
{
i[0] = 12345;
}
...
std::vector<int>& globalArray()
{
static std::vector<int> V;
return V;
}
bool const push_back(std::vector<int>& vec, int v)
{
vec.push_back(v);
return true; // dummy return for static init
}
// module1.cpp
static bool const dummy = push_back(globalArray(), 1);
// module2.cpp
static bool const dummy = push_back(globalArray(), 2);