STD :: خريطة inizialitazion (مرة واحدة فقط)
سؤال
لدي وظيفة تترجم البيانات باستخدام 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 لإدارة وقت الحياة الكائن.