كيفية إنشاء طريقة ثابتة تقوم بتقييم المتغير الثابت المحلي مرة واحدة؟
-
21-09-2019 - |
سؤال
لدي فئة ذات طريقة ثابتة لها متغير ثابت محلي. أريد أن يتم حساب/تقييم هذا المتغير مرة واحدة (المرة الأولى التي أسمي فيها الوظيفة) ولأي احتجاج لاحق ، لم يتم تقييمه بعد الآن. كيف يتم فعل ذلك؟ ها هو صفي:
template<
typename T1 = int, unsigned N1 = 1,
typename T2 = int, unsigned N2 = 0,
typename T3 = int, unsigned N3 = 0,
typename T4 = int, unsigned N4 = 0,
typename T5 = int, unsigned N5 = 0,
typename T6 = int, unsigned N6 = 0,
typename T7 = int, unsigned N7 = 0,
typename T8 = int, unsigned N8 = 0,
typename T9 = int, unsigned N9 = 0,
typename T10 = int, unsigned N10 = 0,
typename T11 = int, unsigned N11 = 0,
typename T12 = int, unsigned N12 = 0,
typename T13 = int, unsigned N13 = 0,
typename T14 = int, unsigned N14 = 0,
typename T15 = int, unsigned N15 = 0,
typename T16 = int, unsigned N16 = 0>
struct GroupAlloc
{
static const uint32_t sizeClass;
static uint32_t getSize()
{
static uint32_t totalSize = 0;
totalSize += sizeof(T1)*N1;
totalSize += sizeof(T2)*N2;
totalSize += sizeof(T3)*N3;
totalSize += sizeof(T4)*N4;
totalSize += sizeof(T5)*N5;
totalSize += sizeof(T6)*N6;
totalSize += sizeof(T7)*N7;
totalSize += sizeof(T8)*N8;
totalSize += sizeof(T9)*N9;
totalSize += sizeof(T10)*N10;
totalSize += sizeof(T11)*N11;
totalSize += sizeof(T12)*N12;
totalSize += sizeof(T13)*N13;
totalSize += sizeof(T14)*N14;
totalSize += sizeof(T15)*N15;
totalSize += sizeof(T16)*N16;
totalSize = 8*((totalSize + 7)/8);
return totalSize;
}
};
تعديل:
شكرا جميع لمساعدتك السريعة. +1 للجميع. لقد اخترت إجابة Tyler McHenry لأنها لا تحتاج إلى أي مقارنة ، وتقييم الوظيفة الثابتة البحتة. سأحتاج إلى هذا الرمز للتخصيص ، لذا تجنب "إذا" يجب أن يكون أفضل. شكرًا لك مرة أخرى!
تعديل:
اتضح أن إجابة GF هي الأفضل لأنها تتعامل مع المهمة أثناء وقت الترجمة وحفظ البرنامج من الصداع الآمن في مؤشرات الترابط والتهيئة الصريحة. ومع ذلك ، أنا أحترم أفضل إجابة السابقة. سأقدم الائتمان هنا بدلاً من تغيير علامة القراد. شكرا للجميع للمساعدة!
المحلول
قم بعمل وظيفة ثابتة أخرى تقوم بالحساب ، واستخدم ذلك لتهيئة المتغير ، على سبيل المثال
static uint32_t computeSize()
{
uint32_t init_totalSize;
// Lots of code
return init_totalSize;
}
static uint32_t getSize()
{
static uint32_t totalSize = computeSize();
return totalSize;
}
يتم ضمان تهيئة المتغيرات الثابتة مرة واحدة (المرة الأولى التي يتم فيها استخدام الوظيفة التي تحتوي عليها).
تعديل: ولكن هذا هو ليس آمن الخيط. تشرح هذه الصفحة السبب بتفصيل كبير.
لجعله آمنًا لخيط الخيط ، لا يكفي لفت تهيئة تهيئة totalSize
(الدعوة إلى computeSize
) في القسم الحاسم ، لأن التهيئة المتغيرة الثابتة هي "سحر التحويل البرمجي" ، ويمكن أن يكون المتغير للخضوع للتهيئة في أي وقت أثناء المكالمة getSize
قبل استخدامه ، حتى قبل البيان الأول للوظيفة. ما عليك القيام به هو منع أكثر من موضوع واحد من الاتصال getSize
في الوقت نفسه ، والتي يمكن إنجازها بمستوى آخر من عدم التوجيه ، على سبيل المثال
static uint32_t computeSize()
{
uint32_t init_totalSize;
// Lots of code
return init_totalSize;
}
static uint32_t real_getSize()
{
static uint32_t totalSize = computeSize();
return totalSize;
}
static uint32_t getSize()
{
uint32_t totalSize;
/* --- Enter Critical Section (acquire lock) -- */
totalSize = real_getSize();
/* --- Exit Critical Section (release lock) -- */
return totalSize;
}
هذا يمنع اثنين من المواضيع من إدخال الوظيفة التي تحتوي على المتغير الثابت في نفس الوقت ، والتأكد من حدوث تهيئته داخل قسم حرج.
نصائح أخرى
انقل الحساب إلى وظيفة المساعد:
static uint32_t totalSize = calculateTotalSize();
سيتم الاحتجاج بوظيفة المساعد فقط عندما totalSize
يتم تهيئتها.
متأخر بعض الشيء ، ولكن لماذا تقوم بحساب وقت تشغيل (يحتمل) هنا على الإطلاق؟ استخدم ثوابت وقت الترجمة ولا يمكنك حتى الحصول على أي مشاكل في الخيوط:
template<
typename T1, unsigned N1,
typename T2, unsigned N2,
/* ... */
>
struct totalSize {
static const uint32_t sum =
sizeof(T1)*N1
+ sizeof(T2)*N2
/* ... */
;
static const uint32_t value =
8*((sum + 7)/8);
};
uint32_t GroupAlloc::getSize() {
return totalSize<T1,N1,T2,N2,/*...*/>::value;
}
شيء مثل:
static uint32_t getSize()
{
static uint32_t totalSize = 0;
static bool computed = 0;
if(computed)
return totalSize;
computed = 1;
// ... go on with your computation
سيفعل الخدعة. لاحظ أنه ليس آمنًا لخيط الخيط.
static uint32_t totalSize = 0; // initialisation performed once only
if ( totalSize == 0 ) {
totalSize += sizeof(T1)*N1;
totalSize += sizeof(T2)*N2;
totalSize += sizeof(T3)*N3;
totalSize += sizeof(T4)*N4;
// etc
}