سؤال

لدي وظيفة تترجم البيانات باستخدام 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];

هل الامور على ما يرام؟ حل أفضل؟

هل كانت مفيدة؟

المحلول

يجب بالتأكيد أن يحسن الحل الثاني من الكفاءة ، ولكنه ليس (على الأقل IMO) أفضل تطبيق ممكن. بادئ ذي بدء ، فإنه يجعل first_time مرئي علنيًا ، على الرغم من أنه فقط variable_to_parameter في الواقع يهتم بذلك. لقد صنعت بالفعل hp متغير ثابت في الوظيفة ، و first_time يجب أن يكون كذلك.

ثانياً ، لن أستخدم المؤشرات و/أو التخصيص الديناميكي لقيم histoparameter. في واحد int واثنين من العوامات ، لا يوجد ببساطة سبب للقيام بذلك. إذا كنت تمرهم حقًا كثيرًا بحيث أصبح النسخ مشكلة ، فمن المحتمل أن تكون أفضل حالًا باستخدام نوع من فئة المؤشرات الذكية بدلاً من مؤشر خام - والأخير يصعب استخدامه وأكثر صعوبة في صنعه استثناء آمن.

ثالثًا ، سأدرس ما إذا كان من المفيد جعل variable_to_parameter في functor بدلاً من وظيفة. في هذه الحالة ، تقوم بتهيئة الخريطة في CTOR ، لذلك لن تضطر إلى التحقق مما إذا كان قد تمت تهيئته في كل مرة operator() تم استدعاء. يمكنك أيضًا الجمع بين الاثنين ، من خلال الحصول على خريطة ثابتة في المسلح. يقوم CTOR بتهيئته إذا لم يكن موجودًا ، ويقوم المشغل () بإجراء بحث.

أخيرًا ، لاحظت ذلك map::operator[] يعد مفيدًا في المقام الأول لإدخال العناصر - إنه ينشئ عنصرًا به المفتاح المحدد إذا لم يكن موجودًا ، ولكن عندما تبحث عن عنصر ، فأنت عادة لا ترغب في إنشاء عنصر. لهذا ، من الأفضل استخدامك بشكل عام map.find() في حين أن.

نصائح أخرى

الحل الثاني يبدو جيدًا بالنسبة لي - يمكنك القول:

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

أود أيضًا أن أفكر في جعلها خريطة للقيم بدلاً من المؤشرات - لا أرى أنك بحاجة إلى تخصيص ديناميكي هنا:

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

من ثم:

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

لاحظ أنك لا تحتاج إلى تحويل Str :: String الصريح. أو الأفضل من ذلك:

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

الحل الأول ينتج الكثير من القمامة. لماذا لا تعيد الفصل بالقيمة؟ إنه خفيف الوزن تمامًا ، ولا تضطر إلى تخصيصه ديناميكيًا.

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 إذا كنت تريدها غير قابلة للتغيير.

تعديل: تمت إضافة Make_pair ، كما اقترح Niel.

سيكون لدي 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];
}

في كلتا الحالتين ، تقوم بإنشاء تسرب الذاكرة. في كل مرة = المشغل يسمى ، على سبيل المثال:

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

أنت تقوم بإنشاء كائن Histoparameter جديد وربط المفتاح "PH" مع هذا الكائن الأحدث ، تاركًا الكائن السابق. إذا كان إنشاء كائن جديد في كل مرة هو نيتك الفعلية ، فربما تحتاج إلى الاتصال

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

قبل new عملية.

اقتراحي هو تجنب الخام new العمليات قدر الإمكان واللجوء إلى المؤشرات الذكية مثل Boost :: share_ptr لإدارة وقت الحياة الكائن.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top