C++ 在c+中定义全局数据的最佳方式是什么+;?
我有一个映射,我想在应用程序启动时构建(在运行时从文件中读取),然后由多个类/函数使用 最好的方法是什么C++ 在c+中定义全局数据的最佳方式是什么+;?,c++,map,global-variables,C++,Map,Global Variables,我有一个映射,我想在应用程序启动时构建(在运行时从文件中读取),然后由多个类/函数使用 最好的方法是什么 Struct GlobalData { static map<int,int> aMap; static void buildMap(); //fill in the map } Struct GlobalData { 静态地图; 静态void buildMap();//填充映射 } 然后在main()中调用GlobalData::buildMap(),稍后使
Struct GlobalData
{
static map<int,int> aMap;
static void buildMap(); //fill in the map
}
Struct GlobalData
{
静态地图;
静态void buildMap();//填充映射
}
然后在main()中调用GlobalData::buildMap(),稍后使用映射GlobalData::someMap
或按以下方式操作:
map<int,int>& getMap()
{
static map<int,int> aMap;
return aMap
}
void buildMap()
map&getMap()
{
静态地图;
返回aMap
}
void buildMap()
然后在main()中调用buildMap()并在以后调用getMap()以获取映射您可以定义一个名为
ApplicationContext
的类。此类的目的是初始化和保存应用程序所需的“全局”数据。您可以将从文件中读取的映射
放在此ApplicationContext
实例中,并允许其他类接受ApplicationContext
的实例并使用其中的映射
例如:
// Part of context's construction would be to read the map
ApplicationContext context;
//... After a while
useMap(context);
ApplicationContext
类看起来像:
class ApplicationContext {
public:
ApplicationContext() {
// Some initial stuff before reading map from file
loadMapFromFile();
// Some global stuff to load after
}
const std::map<int, int>& getMap() const {
return aMap;
}
private:
void loadMapFromFile() {
// Code to read your 'global' map from file.
}
std::map<int, int> aMap;
};
class ApplicationContext{
公众:
ApplicationContext(){
//从文件中读取地图之前的一些初始内容
loadMapFromFile();
//之后要加载的一些全局内容
}
常量std::map&getMap()常量{
返回aMap;
}
私人:
void loadMapFromFile(){
//从文件中读取“全局”地图的代码。
}
映射aMap;
};
您可能希望向ApplicationContext
类添加更多参数,但您已经了解了一般的想法。如果每个对象的构造都接受一个上下文实例,那么您不必在应用程序中使用单例,而且应用程序的初始化就在您的ApplicationContext
阅读内容中。根据你的帖子,我认为这可能是一个很好的解决方案
class GlobalData
{
public:
static GlobalData* getInstance()
{
if (nullptr == sm_Instance) { sm_Instance = new GlobalData(); }
return sm_Instance;
}
map<int, int> getSomeMap() { return m_SomeData; }
private:
static GlobalData* sm_Instance;
map<int, int> m_SomeData;
GlobalData() { buildMap(); }
void buildMap() { /* build map */ }
};
GlobalData* GlobalData::sm_Instance = nullptr;
int main()
{
map<int, int> someMap = GlobalData::getInstance()->getSomeMap();
return 0;
}
类全局数据
{
公众:
静态GlobalData*getInstance()
{
如果(nullptr==sm_实例){sm_实例=new GlobalData();}
返回sm_实例;
}
map getSomeMap(){return m_SomeData;}
私人:
静态全局数据*sm_实例;
映射一些数据;
GlobalData(){buildMap();}
void buildMap(){/*build map*/}
};
GlobalData*GlobalData::sm_Instance=nullptr;
int main()
{
map-someMap=GlobalData::getInstance()->getSomeMap();
返回0;
}
GlobalData
在您的第一个选项中,最好是一个名称空间,因为它的实例是无意义的
在实践中,你们的选择并没有太大的不同。第一个是在main之前构建地图。第二个函数在第一次调用getMap
时构造映射。在任何一种情况下,地图都将填充到main中。如果这样做,那么映射对于在静态初始化期间运行的任何代码都将不可用(在其他转换单元中的静态对象取消初始化期间也不可用)。另一个缺点是您公开了对映射的非常量访问,如果您希望在启动时初始化映射,并且只在以后读取它,这可能是不可取的
可以通过在静态初始化期间填充映射来改善这种情况。Vite Falcons的回答是在静态对象的构造函数中调用buildMap
(重命名为loadMapFromFile
)。这还不够。这是因为映射(或者更确切地说,拥有映射的context
)可以在依赖它的静态对象之前初始化,也可以不初始化
这个答案可以通过在第一次使用时使用construct来改进,但是如果您更喜欢简单而不是热情的封装,那么这里有一个示例,对您的第二个选项进行了最小的更改,它既允许静态对象使用映射,也允许对映射的引用是常量,这是上述封装中最重要的部分
static map<int,int>* buildMap() {
auto aMap = new map<int,int>();
// load the map here
return aMap;
}
const map<int,int>& getMap() { // use const if you don't need to modify the map
static map<int,int>* aMap = buildmap();
return *aMap;
}
静态映射*buildMap(){
自动映射=新映射();
//把地图放在这里
返回aMap;
}
const map&getMap(){//如果不需要修改映射,请使用const
静态映射*aMap=buildmap();
返回*aMap;
}
如果在静态(de)初始化期间不需要使用映射,并且确实希望在初始加载后修改映射,则两个选项都可以。请记住,当有人在某个点上添加一个依赖于映射的静态对象(到另一个翻译单元中)时,程序可能会崩溃(甚至更糟:它可能不会!)。我有一个非常适合您的要求的设计模式,我已经多次使用过它 请阅读密码 简要视图:有一个GlobalData类继承自GlobalDataInfoIface和GlobalDataPopulateFace 用户无法直接访问GlobalData。根据其用途,它只能通过两个接口访问全局数据
class GlobalDataPopulateIface {
public:
virtual void buildMap() = 0;
virtual ~GlobalDataPopulateIface() {}
};
class GlobalDataInfoIface {
public:
virtual map<int,int>& getMap() = 0;
virtual ~GlobalDataInfoIface() {}
};
class GlobalData : public GlobalDataInfoIface, public GlobalDataPopulateIface
{
public:
void buildMap();
map<int,int>& getMap();
private:
// All constructors and destructors are made private
GlobalData ();
~GlobalData ();
GlobalData ( const GlobalData& other );
const GlobalData& operator = ( const GlobalData &other );
map<int,int> aMap;
};
class GlobalDataImplInfo {
public:
CGSimWaveformImplInfo();
~CGSimWaveformImplInfo();
GlobalDataInfoIface* GetGlobalDataInfoIface();
GlobalDataPopulateIface* GetGlobalDataPopulateIface();
static void Destroy();
private:
static GlobalData* global_data;
GlobalDataImplInfo(GlobalDataImplInfo const&);
GlobalDataImplInfo& operator= (GlobalDataImplInfo const&);
};
要使用全局数据的客户端应具有以下代码:
GlobalDataImplInfo global_data;
GlobalDataPopulateIface * global_data_populate = global_data.GetGlobalDataPopulateIface();
GlobalDataImplInfo global_data;
GlobalDataInfoIface * global_data_info = global_data.GetGlobalDataInfoIface();
在这个架构中,我们在架构本身中定义了全局数据的实现者和用户的边界。因此,这有助于引导正确使用全球数据
全局数据的用户无法修改全局数据
如果您不理解代码,请告诉我。我们可以讨论一下。只需使用静态构造函数
Struct GlobalData {
static map<int,int> aMap;
static void buildMap() { ... } //fill in the map
GlobalData() { buildMap(); }
}
GlobalData TheGlobalData;
main() { ... }
Struct GlobalData{
静态地图;
静态void buildMap(){…}//填充映射
GlobalData(){buildMap();}
}
GlobalData the GlobalData;
main(){…}
为了保证正确的初始化,静态构造函数必须与可能使用它的代码位于同一个翻译单元中,例如main()。启动时“是什么意思?映射内容在编译时已知,还是必须在运行时计算?它将在运行时从文件中读取。看起来您应该检查关键字
extern
的使用。然后可能有一个头/cpp文件组合专用于全局