我正在开发一个对象和函数库,并有一个名为 的头文件,super.hpp
其中包含一些初始化任务。
超级.hpp
#ifndef H_INIT
#define H_INIT
#include <iostream>
#include <string>
static bool isInit = false;
struct settings_struct{
std::string path = "foo";
void load(){ path = "bar"; }
};
struct initializer_struct{
settings_struct settings;
initializer_struct(){
if(!isInit){
std::cout << "Doing initialization\n";
settings.load();
isInit = true;
}
// settings.load();
}//====================
~initializer_struct(){
if(isInit){
std::cout << "Doing closing ops\n";
isInit = false;
}
}
};
static initializer_struct init; // static declaration: only create one!
#endif
我使用此标头的目的是创建一次initializer_struct
对象;当它被构造时,这个结构会执行一些为整个库设置标志和设置的操作。其中一项操作是创建从 XML 文件加载设置的设置结构;此操作也应该只在构造 init 结构时发生一次,因此变量(此处为)是从设置文件中保存的。标头包含在库中的所有对象中,因为不同的对象以不同的容量使用,即无法预测哪些对象将在应用程序中使用,因此我将标头包含在所有对象中以保证它被称为 no使用哪些对象无关紧要。path
super.hpp
super.hpp
我的问题是:当我包含super.hpp
在多个由主应用程序加载的类/对象中时,结构init
似乎被重新初始化,并且在settings_struct
构造时设置的变量被默认值覆盖。要查看此操作,请考虑以下附加文件:
测试.cpp
#include "classA.hpp"
#include "classB.hpp"
#include <iostream>
int main(int argc, char *argv[]){
(void) argc;
(void) argv;
classA a;
classB b;
std::cout << "Settings path = " << init.settings.path << std::endl;
std::cout << "Class A Number = " << a.getNumber() << std::endl;
std::cout << "Class B Number = " << b.getInteger() << std::endl;
}
A类.hpp
#ifndef H_CLASSA
#define H_CLASSA
class classA{
private:
double number;
public:
classA() : number(7) {}
double getNumber();
};
#endif
类A.cpp
#include "super.hpp"
#include "classA.hpp"
double classA::getNumber(){ return number; }
B类.hpp
#ifndef H_CLASSB
#define H_CLASSB
class classB{
private:
int number;
public:
classB() : number(3) {}
int getInteger();
};
#endif
B类.cpp
#include "super.hpp"
#include "classB.hpp"
int classB::getInteger(){ return number; }
要编译并运行示例,
g++ -std=c++11 -W -Wall -Wextra -Weffc++ -pedantic -c classA.cpp -o classA.o
g++ -std=c++11 -W -Wall -Wextra -Weffc++ -pedantic -c classB.cpp -o classB.o
g++ -std=c++11 -W -Wall -Wextra -Weffc++ -pedantic classA.o classB.o test.cpp -o test.out
./test.out
我希望 test.out 的输出如下:
Doing initialization
Settings path = bar
Number = 7
Doing closing ops
但是,当我运行它时,我会得到“设置路径 = foo”。因此,我的结论是 , initializer_struct
,init
被构造了不止一次。第一次,布尔isInit
值为假,设置结构load
函数设置path
为“bar”。对于所有后续初始化,isInit
为真,因此load
不会再次调用该函数,并且似乎未初始化settings
(即path = "foo"
)中的变量值覆盖了先前加载的值,因此init.settings.path
in的输出test.cpp
。
为什么是这样?为什么init
每次包含标头时都构造对象?我原以为包含守卫会阻止标题代码被多次调用。如果我init
在test.hpp
非静态变量中创建变量,则会创建多个副本,并且输出会打印“正在执行初始化”和“正在执行关闭操作”的多次迭代。此外,如果我settings.load()
在构造函数中取消注释条件语句之外的函数调用initializer_struct()
,则输出会给出“bar”的设置路径。最后,删除super.hpp
from的包含会classA.cpp
导致路径值为“bar”,这进一步支持了我的假设,即多个包含test.hpp
导致多个构造函数调用。
我想避免使用settings.load()' called for every object that includes
super.hpp` - 这就是我将命令放在条件语句中的原因。有什么想法吗?如何确保设置文件只读取一次并且加载的值不会被覆盖?这是设置我的库使用的一些标志和设置的完全钝的方法吗?如果是这样,您有什么建议可以使流程更简单和/或更优雅吗?
谢谢!
编辑:更新以包括两个对象类以更接近地代表我更复杂的设置