سؤال

هل يعرف أحد كيف يمكنني، في كود C++ المستقل عن النظام الأساسي، منع إنشاء كائن على الكومة؟أي بالنسبة للفئة "Foo"، أريد منع المستخدمين من القيام بذلك:

Foo *ptr = new Foo;

والسماح لهم فقط بالقيام بذلك:

Foo myfooObject;

هل لدى أي شخص أي أفكار؟

هتافات،

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

المحلول

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

private:
    void* operator new(size_t);          // standard new
    void* operator new(size_t, void*);   // placement new
    void* operator new[](size_t);        // array new
    void* operator new[](size_t, void*); // placement array new

(قد تقترح ممارسات الترميز الجيدة أنه يجب عليك أيضًا التحميل الزائد على عاملي الحذف والحذف[] - سأفعل ذلك، ولكن بما أنه لن يتم استدعاؤهم، فلن يتم الاتصال بهم) حقًا ضروري.)

بولدو من الصحيح أيضًا أن هذا لا يستمر في التجميع على Foo، على الرغم من أنه يرث من Foo.يمكنك القيام ببعض سحر البرمجة الوصفية للقالب للمساعدة في منع ذلك، لكنه لن يكون محصنًا ضد "المستخدمين الأشرار" وبالتالي ربما لا يستحق هذا التعقيد.إن توثيق كيفية استخدامه، ومراجعة التعليمات البرمجية للتأكد من استخدامه بشكل صحيح، هي الطريقة الوحيدة بنسبة 100٪ تقريبًا.

نصائح أخرى

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

class Foo {
private:
  void* operator new(size_t size);
};

ملاحظة.نعم، أعلم أن هذا يمكن التحايل عليه بسهولة.أنا لا أوصي بذلك حقًا - أعتقد أنها فكرة سيئة - كنت أجيب على السؤال فقط!؛-)

لا أعرف كيفية القيام بذلك بشكل موثوق وبطريقة محمولة ..لكن..

إذا كان الكائن موجودًا على المكدس، فقد تتمكن من التأكيد داخل المُنشئ أن قيمة "هذا" تكون دائمًا قريبة من مؤشر المكدس.هناك احتمال كبير أن يكون الكائن موجودًا في المكدس إذا كان هذا هو الحال.

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

FooClass::FooClass() {
    char dummy;
    ptrdiff_t displacement = &dummy - reinterpret_cast<char*>(this);
    if (displacement > 10000 || displacement < -10000) {
        throw "Not on the stack - maybe..";
    }
}

@ نيك

يمكن التحايل على ذلك عن طريق إنشاء فئة مشتقة من Foo أو مجمعة.أعتقد أن ما أقترحه (رغم أنه ليس قويًا) سيظل صالحًا للفئات المشتقة والمجمعة.

على سبيل المثال:

struct MyStruct {
    Foo m_foo;
};

MyStruct* p = new MyStruct();

لقد قمت هنا بإنشاء مثيل لـ "Foo" على الكومة، متجاوزًا عامل التشغيل المخفي الجديد لـ Foo.

نظرًا لأن رؤوس التصحيح يمكن أن تتجاوز التوقيع الجديد للمشغل، فمن الأفضل استخدام ...التوقيعات كعلاج كامل:

private:
void* operator new(size_t, ...) = delete;
void* operator new[](size_t, ...) = delete;

يمكنك الإعلان عن وظيفة تسمى "عامل التشغيل الجديد" داخل فئة Foo والتي من شأنها أن تمنع الوصول إلى الشكل العادي للجديد.

هل هذا هو نوع السلوك الذي تريده؟

يمكنك الإعلان عنها كواجهة والتحكم في فئة التنفيذ بشكل مباشر أكثر من التعليمات البرمجية الخاصة بك.

يمكن منع ذلك عن طريق جعل المُنشئين خاصين وتوفير عضو ثابت لإنشاء كائن في المكدس

Class Foo
{
    private:
        Foo();
        Foo(Foo& );
    public:
        static Foo GenerateInstance() { 
            Foo a ; return a; 
        }
}

سيؤدي هذا إلى إنشاء الكائن دائمًا في المكدس.

لست متأكدًا مما إذا كان هذا يوفر أي فرص لوقت الترجمة، ولكن هل فكرت في التحميل الزائد على عامل التشغيل "الجديد" لفصلك؟

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