我有一个地图,我想在应用程序启动时构建(在运行时从文件中读取),然后由多个类/函数使用。
最好的方法是什么?
Struct GlobalData
{
static map<int,int> aMap;
static void buildMap(); //fill in the map
}
然后在main()中调用GlobalData :: buildMap()并稍后使用地图GlobalData :: someMap
或者按照以下方式执行:
map<int,int>& getMap()
{
static map<int,int> aMap;
return aMap
}
void buildMap()
然后在main()中调用buildMap()并调用getMap()以稍后获取地图
答案 0 :(得分:1)
了解Singleton。根据你的帖子,我认为这可能是一个很好的解决方案。
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;
}
答案 1 :(得分:1)
只需使用静态构造函数。
Struct GlobalData {
static map<int,int> aMap;
static void buildMap() { ... } //fill in the map
GlobalData() { buildMap(); }
}
GlobalData TheGlobalData;
main() { ... }
为了保证正确的初始化,静态构造函数必须与可能使用它的代码位于相同的转换单元中,例如main()。
答案 2 :(得分:0)
您可以定义一个名为ApplicationContext
的类。本课程的目的是初始化并保持“全球化”。您的应用程序所需的数据。您可以将您从文件中读取的Map
放在此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;
};
您可能希望为ApplicationContext
课程添加更多参数,但您可以获得一般性的想法。如果每个对象的构造都接受上下文的实例,那么您不必在应用程序中使用单例,并且应用程序的初始化位于ApplicationContext
内。
答案 3 :(得分:0)
GlobalData
也可能是命名空间,因为它的实例毫无意义。
您的选择在实践中彼此并无太大差异。第一个在main之前构造地图。第二个是在第一次调用getMap
时构建地图。在任何一种情况下,地图都将填充在main中。如果这样做,那么地图将无法用于在静态初始化期间运行的任何代码(在其他翻译单元中静态对象的去初始化期间它也无法使用)。另一个缺点是你暴露了对地图的非常量访问,如果你想在开始时初始化地图而只是稍后阅读它,这可能是不可取的。
通过在静态初始化期间填充地图可以改善这种情况。 Vite Falcons&#39;答案通过在静态对象的构造函数中调用buildMap
(重命名为loadMapFromFile
)来完成此操作。这仍然不够。这是因为地图(或者更确切地说,拥有地图的context
)可能会或者可能不会在依赖它的静态对象之前进行初始化。
通过使用构造首次使用的习惯用法可以改善这个答案,但是如果你喜欢简单而不是热心的封装,这里有一个例子,对你的第二个选项进行了微小的改动,它们都允许地图由静态对象使用,并允许对map的引用为const,这是所提到的封装中最重要的部分。
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;
}
如果您不想在静态(de)初始化期间使用地图,并且您确实想在初始加载后修改地图,那么您的任何一个选项都可以。请记住,当某人在某个时刻添加一个依赖于地图的静态对象(进入另一个翻译单元)时,程序可能会中断(或者更糟糕的是:它可能不会!)。
答案 4 :(得分:0)
我的设计模式非常适合您的要求,我已多次使用它。
请阅读代码。
简要说明:有一个GlobalData类,它继承自GlobalDataInfoIface和GlobalDataPopulateIface。
用户无法直接访问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();
在这个架构中,我们已经定义了架构本身中全局数据的实现者和用户的边界。因此,有助于引导全球数据的正确使用。
全局数据用户无法修改全局数据。
如果您不理解代码,请告诉我。我们可以讨论一下。