std :: map inizialitazion(只有一次)

时间:2010-01-25 22:11:55

标签: c++ map std garbage

我有一个使用std :: map

翻译数据的函数
struct HistoParameter
{
  int nbins;
  float first;
  float last;
  HistoParameter(int _nbins, int _first, int _last) :
    nbins(_nbins), first(_first), last(_last) {};
};

HistoParameter* variable_to_parameter(char* var_name)
{
  std::map<const std::string, HistoParameter*> hp;
  hp[std::string("ph_pt")] = new HistoParameter(100,0,22000);
  hp[std::string("ph_eta")] = new HistoParameter(100,-3,3);
  // ...
  return hp[var_name];
}

我的结构很轻,但图像很重。问题在于,每次调用此函数时,它都会创建很多HistoParameter对象,也许切换案例效率更高。第一个问题:我在创造垃圾?

第二个解决方案:

bool first_time = true;
HistoParameter* variable_to_parameter(char* var_name)
{
  static std::map<const std::string, HistoParameter*> hp;
  if (first_time)
    {
  hp[std::string("ph_pt")] = new HistoParameter(100,0,22000);
  hp[std::string("ph_eta")] = new HistoParameter(100,-3,3);
  // ...
    }
  first_time = false;
  return hp[var_name];

没关系?更好的解决方案?

5 个答案:

答案 0 :(得分:4)

第二种解决方案似乎对我好 - 你可以说:

if ( hp.empty() ) {
   // populate map
}

我还会考虑将它作为值的映射而不是指针 - 我不认为你需要动态分配:

 std::map <std::string, HistoParameter> hp;

然后:

 hp["ph_pt"] = HistoParameter(100,0,22000);

请注意,您不需要显式的std :: string转换。或者更好的是:

 hp.insert( std::make_pair( "ph_pt", HistoParameter(100,0,22000 )));

答案 1 :(得分:3)

第一种解决方案会产生大量垃圾。你为什么不按价值归还班级?它非常轻巧,你不必动态分配它。

HistoParameter variable_to_parameter(char* var_name)
{
  static std::map<const std::string, HistoParameter> hp;
  if ( hp.empty() )
  {
    hp.insert( std::make_pair( "ph_pt", HistoParameter(100,0,22000) ) );
    hp.insert( std::make_pair( "ph_eta", HistoParameter(100,-3,3) ) );
  //...
  }
  return hp[var_name];
}

如果返回的课程变大,而您想要一个电动工具,请尝试boost::flyweight

如果您不想传回大型结构,可以执行以下操作:

HistoParameter& variable_to_parameter(char* var_name)
{
  // same code
}

...如果你想要它不可变,甚至可以投入const

修改:按照Niel的建议添加了make_pair。

答案 2 :(得分:1)

您的第二个解决方案当然应该提高效率,但不是(至少IMO)可能的最佳实施。首先,它使first_time公开可见,即使只有variable_to_parameter实际关心它。您已在函数中为hp设置了静态变量,first_time也应如此。

其次,我不会对HistoParameter值使用指针和/或动态分配。在一个int和两个浮点数中,根本没有理由这样做。如果你真的传递它们以至于复制成为一个问题,你可能最好使用某种智能指针类而不是原始指针 - 后者更难以使用而且更难以制作例外安全。

第三,我会考虑将variable_to_parameter变为函数而不是函数是否值得。在这种情况下,您将在ctor中初始化地图,因此您不必每次调用operator()时都检查它是否已初始化。您还可以通过在仿函数中使用静态地图来组合这两者。如果它不存在,则ctor初始化它,operator()只进行查找。

最后,我注意到map::operator[]主要用于插入项目 - 如果项目不存在则创建具有指定键的项目,但是当您查找项目时,通常不想创建一个项目。为此,您通常最好使用map.find()

答案 3 :(得分:0)

我有一个std :: map&lt; std :: string,HistoParameter *&gt;会员并做

InitializeHistoParameter() 
{
   myMap["ph_pt"] = new ...
   myMap["ph_eta"] = new ...
}

然后

HistoParameter* variable_to_parameter(char* var_name) 
{
    return myMap[var_name];
}

答案 4 :(得分:0)

无论哪种方式,您都在创建内存泄漏。 每次调用=运算符时,例如:

hp[std::string("ph_pt")] = new HistoParameter(100,0,22000);

您正在创建一个新的HistoParameter对象,并将关键字“ph”与此最新对象配对,让前一个对象悬空。 如果每次创建一个新对象是您的实际意图,您可能需要调用

delete hp[std::string("ph_pt")]; 
new操作之前

我的建议是尽可能避免原始new操作,并使用boost::share_ptr等智能指针进行对象生命周期管理。