1

我有一个使用 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 对象,也许一个 switch case 更有效。第一个问题:我在制造垃圾?

第二种解决方案:

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];

可以吗?更好的解决方案?

4

5 回答 5

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 )));
于 2010-01-25T22:18:27.477 回答
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。

于 2010-01-25T22:18:26.367 回答
1

您的第二个解决方案当然应该提高效率,但(至少 IMO)不是最好的实现。首先,它使first_time公众可见,尽管variable_to_parameter实际上只关心它。您已经hp在函数中创建了一个静态变量,并且first_time应该也是。

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

第三,我会考虑将 variable_to_parameter 变成仿函数而不是函数是否值得。在这种情况下,您将在 ctor 中初始化映射,因此您不必在每次operator()调用时检查它是否已初始化。您也可以将两者结合起来,方法是在函子中有一个静态映射。如果它不存在,ctor 会对其进行初始化,并且 operator() 只是进行查找。

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

于 2010-01-25T22:27:14.693 回答
0

我会有一个 std::map< std::string, HistoParameter *> 成员并做

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

接着

HistoParameter* variable_to_parameter(char* var_name) 
{
    return myMap[var_name];
}
于 2010-01-25T22:19:58.143 回答
0

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

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

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

delete hp[std::string("ph_pt")]; 

手术前new

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

于 2010-01-26T04:31:42.150 回答