سؤال

لدي تنفيذ مؤشرات السيارات:

template <typename T, bool Arr = false>
class GAutoPtr
{
    T *Ptr;

public:
    typedef GAutoPtr<T, Arr> &AutoPtrRef;

    GAutoPtr(T *ptr = 0)
    {
        Ptr = ptr;
    }

    GAutoPtr(AutoPtrRef p)
    {
        Ptr = p.Release();
    }

    ~GAutoPtr() { Empty(); }
    operator T*() { return Ptr; }
    T *Get() { return Ptr; }
    T *operator->() const { LgiAssert(Ptr); return Ptr; }

    inline void Empty()
    {
        if (Arr)
            delete [] Ptr;
        else
            delete Ptr;
        Ptr = 0;
    }

    AutoPtrRef operator =(GAutoPtr<T> p)
    {
        Empty();
        Ptr = p.Ptr;
        p.Ptr = 0;
        return *this;
    }

    void Reset(T *p)
    {
        if (p != Ptr)
        {
            Empty();
            Ptr = p;
        }
    }

    T *Release()
    {
        T *p = Ptr;
        Ptr = 0;
        return p;
    }
};

typedef GAutoPtr<char, true> GAutoString;
typedef GAutoPtr<char16, true> GAutoWString;

وهذا يعمل بشكل جيد في Visual C ++ 6. ومع ذلك في Visual C ++ 2005 أو 2008 لا أستطيع إرجاع مؤشرات السيارات من وظيفة دون أشياء تسير بشكل فظيع.

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

GAutoString Func()
{
    char *s = new char[4];
    strcpy(s, "asd");
    return s;
}

int main()
{
    GAutoString a = Func();
    /// a.Ptr is now garbage
}

ما يحدث هو أن المحول البرمجي يخلق Gautostring مؤقتا لعقد قيمة الإرجاع لهذه الوظيفة، ثم في تمرير ذلك إلى المتغير "A" على المكدس يدعو المشغل T * () من متغير TEMP، ثم GautoPtr ( T * PTR = 0) منشئ، بدلا من مجرد استخدام منشئ النسخ: GautoPtr (AutoPTRREF P)

يؤدي ذلك إلى حذف Temp Auto Auto PTR الذاكرة و "a" يحمل مؤشرا إلى الذاكرة المحررة.

ومع ذلك في VC6، اتصل بالبناء المناسب. الآن في قول كل هذا أستخدم أيضا دول مجلس التعاون الخليجي على Linux و Mac، لذلك أيا كان الرمز الذي أكتبه يحتاج إلى العمل هناك أيضا. يمنعك VC2008 من استخدام متغير قيمة غير ثابتة حسب منشئ النسخ. أيضا لا أريد "const" على أي حال، لأن منشئ النسخ يأخذ ملكية كتلة الذاكرة التي تزيل الملكية من الكائن الذي يتم نسخه ... وبالتالي تعديله.

كيف يمكنني إجراء هذا العمل في VC 2005/2008؟

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

المحلول

هل تجميع هذا حتى تحت G ++ الأخيرة؟ جربته على MacBook Pro و:

xxx.cpp: In function ‘AutoString func()’:
xxx.cpp:52: error: no matching function for call to ‘AutoPtr<char, true>::AutoPtr(AutoString)’
xxx.cpp:12: note: candidates are: AutoPtr<T, isArray>::AutoPtr(AutoPtr<T, isArray>&) [with T = char, bool isArray = true]
xxx.cpp:9: note:                 AutoPtr<T, isArray>::AutoPtr(T*) [with T = char, bool isArray = true]
xxx.cpp:52: error:   initializing temporary from result of ‘AutoPtr<T, isArray>::AutoPtr(T*) [with T = char, bool isArray = true]’

الطريقة الوحيدة التي يمكنني الحصول عليها لتجميعها هي من خلال جعل منشئ النسخ يأخذ const المرجع الذي هو ما اشتبهت. يبدو وكأنه عشبة سوتر نشرت عن شيء مماثل جدا لهذا في أحدث getw. لن أحاول تكرار الدلالية لنقل الملكية std::auto_ptr دون سبب وجيه للغاية. قد ترغب في النظر إلى الأشياء الجيدة المختلفة في boost.smartptr.. وبعد إذا كان ذلك ممكنا، استخدمها بدلا من ذلك.

إذا كنت لا تستطيع زيادة لأي سبب من الأسباب، ثم قراءة المفضلة لديك std::auto_ptr التنفيذ ودفع اهتماما خاصا ل std::auto_ptr_ref صف دراسي. بمجرد أن تفهم لماذا هو هناك والضبط كيف يفعل ما يفعله، ثم العودة وكتابة فئة PTR السيارات. يوجد هذا الفصل للتجول في المشكلة التي تراها. IIRC، تمت مناقشة هذا في بعض التفاصيل في Josuttis ': مكتبة C ++ القياسية. وبعد أعتقد أن هذا هو المكان الذي فهمته حقا لأول مرة.

نصائح أخرى

يمكنك وضع علامة على المنشئ الذي يأخذ حجة T * مع الكلمة الأساسية "الصريحة". لقد تحققت من أن هذا يعمل ويمنع إنشاء الكائن المؤقت الزائفي أيضا، وهو تحسين الأداء. أي شخص يستخدم هذا المنشئ لم يعد بإمكانه الاعتماد على قواعد تحويل نوع المحول البرمجي، على الرغم من ذلك. على سبيل المثال، ستتغير وظيفة إلى هذا:

GAutoString Func()
{
    char *s = new char[4];
    strcpy(s, "asd");
    return GAutoString(s);
}

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

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