سؤال

هل يمكنني التحكم في ترتيب تدمير الكائنات الثابتة؟هل هناك أي طريقة لتنفيذ طلبي المطلوب؟على سبيل المثال، لتحديد بطريقة ما أنني أرغب في تدمير كائن معين أخيرًا، أو على الأقل بعد كائن ثابت آخر؟

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

المحلول

ودمر الكائنات ثابتة في ترتيب عكسي من البناء. وترتيب البناء من الصعب جدا السيطرة عليها. الشيء الوحيد الذي يمكن أن يكون متأكدا من أن كائنين محددة في وحدة تجميع نفسها سيتم بناؤها في ترتيب تعريف. أي شيء آخر هو أكثر أو أقل عشوائي.

نصائح أخرى

والأجوبة الأخرى لهذا يصر أنه لا يمكن القيام به. وهم على حق، وفقا لالمواصفات - ولكن هناك <م> هو خدعة سيتيح لك ان تفعل ذلك

إنشاء فقط <م> واحدة متغير ثابت، من فئة أو بنية الذي يحتوي على كافة الأشياء الأخرى التي من شأنها أن تجعل عادة المتغيرات ثابتة، كما يلي:

class StaticVariables {
    public:
    StaticVariables(): pvar1(new Var1Type), pvar2(new Var2Type) { };
    ~StaticVariables();

    Var1Type *pvar1;
    Var2Type *pvar2;
};

static StaticVariables svars;

ويمكنك إنشاء المتغيرات في أي ترتيب أنت بحاجة إلى ذلك، والأهم من ذلك، <م> تدمير لهم في أي ترتيب أنت بحاجة إلى ذلك، في منشئ والمدمر لStaticVariables. لجعل هذا شفافة تماما، يمكنك إنشاء مراجع ثابتة لمتغيرات جدا، كما يلي:

static Var1Type &var1(*svars.var1);

وفويلا - السيطرة الكاملة. :-) وقال ان هذا هو العمل الإضافي، وغير ضرورية بشكل عام. ولكن عندما <م> هو لزم الأمر، فإنه من المفيد جدا أن نعرف عن ذلك.

والجواب باختصار: بشكل عام، لا

وأطول قليلا الإجابة: للحصول على الأجسام الساكنة العالمية في ترجمة وحدة واحدة من أجل التهيئة هو أعلى إلى أسفل، من اجل التدمير عكس بالضبط. ترتيب بين عدة وحدات الترجمة غير معرف.

إذا كنت حقا بحاجة الى ترتيب معين، تحتاج إلى جعل هذا الأمر بنفسك.

يتم تدمير الكائنات الثابتة بعكس الترتيب الذي تم إنشاؤها به (على سبيل المثال.يتم تدمير الكائن الذي تم إنشاؤه لأول مرة أخيرًا)، ويمكنك التحكم في التسلسل الذي يتم به إنشاء الكائنات الثابتة، باستخدام التقنية الموضحة في البند 47، "تأكد من تهيئة الكائنات العامة قبل استخدامها"في كتاب مايرز فعالة C ++.

على سبيل المثال، لتحديد بطريقة ما أنني أرغب في تدمير كائن معين أخيرًا، أو على الأقل بعد إجراء عملية ثابتة أخرى؟

تأكد من أنه تم إنشاؤه قبل الكائن الثابت الآخر.

كيف يمكنني التحكم في أمر البناء؟ليست كل الإحصائيات موجودة في نفس ملف dll.

سأتجاهل (للتبسيط) حقيقة أنهم ليسوا في نفس ملف DLL.

إن إعادة صياغتي للبند 47 من مايرز (الذي يبلغ طوله 4 صفحات) هي كما يلي.بافتراض أنه تم تعريفك عالميًا في ملف رأس مثل هذا ...

//GlobalA.h
extern GlobalA globalA; //declare a global

...أضف بعض التعليمات البرمجية إلى ملف التضمين مثل هذا ...

//GlobalA.h
extern GlobalA globalA; //declare a global
class InitA
{
  static int refCount;
public:
  InitA();
  ~InitA();
};
static InitA initA;

سيكون تأثير ذلك هو أن أي ملف يتضمن GlobalA.h (على سبيل المثال، ملف المصدر GlobalB.cpp الخاص بك والذي يحدد المتغير العام الثاني الخاص بك) سيحدد مثيلًا ثابتًا لفئة InitA، والذي سيتم إنشاؤه قبل أي شيء آخر في ذلك الملف المصدر (على سبيل المثال.قبل المتغير العالمي الثاني).

تحتوي فئة InitA هذه على عداد مرجعي ثابت.عندما يتم إنشاء مثيل InitA الأول، والذي أصبح الآن مضمونًا قبل إنشاء مثيل GlobalB الخاص بك، يمكن لمنشئ InitA القيام بكل ما يجب عليه فعله لضمان تهيئة مثيل globalA.

ولا توجد طريقة للقيام بذلك في قياسي C ++ ولكن إذا كان لديك معرفة جيدة مترجم معينة الداخلية أنه لا يمكن أن يتحقق على الأرجح.

وفي Visual C ++ المؤشرات إلى وتقع في الجزء .CRT$XI وظائف ال init ثابتة (لC نوع الحرف الأول ثابت) أو شريحة .CRT$XC (لC ++ نوع الحرف الأول ثابت) رابط يجمع جميع الإعلانات ويدمج لهم أبجديا. يمكنك التحكم في الترتيب الذي يحدث التهيئة ثابتة بإعلان الأشياء الخاصة بك في هذا الجزء السليم باستخدام

#pragma init_seg

وعلى سبيل المثال، إذا كنت تريد ملف الأجسام A ليتم إنشاؤها من قبل ملف باء:

وملف A.cpp:

#pragma init_seg(".CRT$XCB")
class A{}A;

وملف B.cpp:

#pragma init_seg(".CRT$XCC")
class B{}B;

ويحصل اندمجت .CRT$XCB في قبل .CRT$XCC. عندما بالتكرار CRT من خلال ثابتة مؤشرات الدالة ال init أنها سوف تواجه ملف A قبل ملف B.

في WATCOM هذا الجزء هو الحادي عشر والاختلافات على تهيئة #pragma يمكن التحكم البناء:

#pragma initialize before library
#pragma initialize after library
#pragma initialize before user

... راجع وثائق لأكثر

لا، لا يمكنك. يجب أن لا تعتمد على الأخرى من بناء / تدمير الأجسام الساكنة.

ويمكنك دائما استخدام المفرد للسيطرة على ترتيب بناء / تدمير الموارد العالمية الخاصة بك.

هل كنت حقا بحاجة المتغير ليتم تهيئتها قبل main؟

إذا كنت لا يمكنك استخدام لغة بسيطة للسيطرة على الواقع من أجل البناء والهدم بكل سهولة، انظر هنا:

#include <cassert>

class single {
    static single* instance;

public:
    static single& get_instance() {
        assert(instance != 0);
        return *instance;
    }

    single()
    // :  normal constructor here
    {
        assert(instance == 0);
        instance = this;
    }

    ~single() {
        // normal destructor here
        instance = 0;
    }
};
single* single::instance = 0;

int real_main(int argc, char** argv) {
    //real program here...

    //everywhere you need
    single::get_instance();
    return 0;
}

int main(int argc, char** argv) {
    single a;
    // other classes made with the same pattern
    // since they are auto variables the order of construction
    // and destruction is well defined.
    return real_main(argc, argv);
}

والأمر لا يتوقف عند محاولة لكم فعلا لإنشاء مثيل الثاني من الدرجة، ولكن إذا قمت بذلك ستفشل التأكيد. في تجربتي أنه يعمل بشكل جيد.

ويمكنك تحقيق فعال وظائف مماثلة من خلال وجود static std::optional<T> بدلا من T. مجرد تهيئة فإنه كما كنت تفعل مع متغير، مع استخدام المراوغة وتدميره عن طريق تعيين std::nullopt (أو لدفعة، boost::none).

وانها مختلفة من وجود المؤشر في الذاكرة التي تمت preallocated، وهو أعتقد أن ما تريد. ولذلك، إذا تدميره و(ربما في وقت لاحق من ذلك بكثير) إعادة إنشائها، وجوه لديك نفس العنوان (والتي يمكن أن تبقي) وكنت لا تدفع تكلفة دينامية تخصيص / إلغاء تخصيص في ذلك الوقت.

استخدم boost::optional<T> إذا لم يكن لديك std:: / std::experimental::.

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