سؤال

أنا أستخدم C++ مع مكتبة OpenCV، وهي عبارة عن مكتبة لمعالجة الصور على الرغم من أن ذلك ليس له صلة بهذا السؤال.حاليا لدي قرار التصميم لاتخاذ.

OpenCV، كونها مكتبة C، لديها هياكل البيانات الخاصة بها (مثل CvMat) المعلنة كبنيات.لإنشائها، يمكنك استخدام وظائف مثل cvCreateMat، ولإصدارها، يمكنك استخدام وظائف مثل cvReleaseMat.كوني مبرمج C++، قمت بإنشاء ملف خاص cv_scoped فئة والتي من شأنها أن تستدعي cvReleaseMat تلقائيًا عندما تخرج عن النطاق (مثل boost::scoped_ptr).

ما أدركه الآن هو أنني أتمنى أن أستفيد منه auto_ptr و shared_ptr في الحالات كذلك.أشعر فقط أن كتابة التعليمات البرمجية لنفسي cv_auto_ptr و cv_shared_ptr ستكون الدروس فكرة سيئة، ناهيك عن مضيعة للوقت.لذا كنت أبحث عن حلول، وتوصلت إلى ثلاثة احتمالات.

أولاً, يمكنني استخدام فئة cv_scoped التي أنشأتها بالفعل.سأعيد تسميته إلى cv_ptr ثم استخدم المؤشرات الذكية مثل ذلك: std::auto_ptr<cv_ptr>.الشيء المزعج في هذا الأمر هو أنني سأضطر دائمًا إلى إلغاء الإشارة مرتين:

std::auto_ptr<cv_ptr> matrix(cv_ptr(cvCreateMat(320, 240, CV_32FC3)));
cvPow(matrix.get()->get()); // one get for the auto_ptr, one for the cv_ptr

أعلم أنه يبدو أنني أستطيع الإعلان عن تحويل ضمني، لكنني لا أستطيع ذلك في الواقع - فمعظم وظائف OpenCV تحتوي على المعلمة void* - لذلك لن يتم استدعاء أي تحويل ضمني.أرغب حقًا في طريقة للقيام بذلك حيث لا أضطر إلى القيام بالإسناد المزدوج.

ثانية, ، يمكنني تجاوز بطريقة أو بأخرى operator delete.لا أريد تجاوز حذف عامل التشغيل العالمي لأنني أريد فقط أن ينطبق هذا على أنواع CvMat (وبعض الأنواع الأخرى).ومع ذلك، لا أستطيع تغيير المكتبة، لذلك لا أستطيع الإضافة operator delete إلى بنية CvMat.لذلك لا أعرف كيف سيعمل هذا.

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

class cv_auto_ptr {
public:
  cv_auto_ptr();
  ~cv_auto_ptr();

  // each method would just be a proxy for the smart pointer
  CvMat* get() { return this->matrix_.get()->get(); }
  // all the other operators/methods in auto_ptr would be the same, you get the idea

private:
  auto_ptr<cv_ptr> matrix_; // cv_ptr deletes CvMat properly
}

ماذا ستفعل في موقفي؟الرجاء مساعدتي في معرفة هذا.

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

المحلول

وصممت auto_ptr حقا لRAII على C ++ فئة مع ثوابت / تالفة كنت تدفع استخداماتها هنا إلى الأشياء التي ربما لا ينبغي أن تستخدم ل(ولكن يمكن).

وعلى أي حال don'y كنت تريد أن تكون قادرة على استخدام مساعيكم C ++ الكائن كما لو كان متغير كومة العادي من دون تخصيص كل مرة حيوي؟

والحل القياسي لمشكلتك هو إنشاء مجمع مع منشئ / المدمر.
ولكن لجعلها صالحة للاستعمال من قبل وظائف C فقط إضافة عامل يلقي الداخلية لذلك لصناعة السيارات في سحرية تحول نفسها إلى كائن C عند تمريرها إلى وظيفة C

وكتابة فئة مجمع.

class Mat
{
    CvMat* impl;
    public:
        Mat(/* Constructor  Arguments */)
        {
            impl = cvCreateMat(/* BLAH */);
        }
        ~Mat()
        {
            cvReleaseMat(impl);
        }
        operator CvMat*()
        {   // Cast opertator. Convert your C++ wrapper object into C object
            // when you use it with all those C functions that come with the
            // library.

            return impl;
        }
};

void Plop(CvMat* x)
{   // Some C function dealing with CvMat
}

int main()
{                            // Don't need to dynamically allocate
    Mat                  m;  // Just create on the stack.
    Plop(m);                 // Call Plop directly

    std::auto_ptr<Mat>   mP(new Mat);
    Plop(*mP);
}

نصائح أخرى

ونهج واحد التي يمكن أن تنظر هو استخدام حقيقة أن std::tr1::shared_ptr ديه وظيفة لتوفير deleter المخصصة. ليس لدي إلمام مكتبة برمجية مفتوحة للرؤية الحاسوبية لذلك أنا استنتاج من ما كنت قد كتبت.

struct CvMatDeleter
{
    void operator( CvMat* p ) { cvReleaseMat( p ) ; }
};

void test()
{
    std::tr1::shared_ptr< CvMat > pMat( cvCreateMat(320, 240, CV_32FC3), CvMatDeleter() );
    // . . .
}

ولأن deleter هو مخزن في مؤشر المشتركة يمكنك فقط استخدام ما هو طبيعي وعندما يحتاج المؤشر الخام المشتركة أخيرا المراد حذفه، وسوف يطلق cvReleaseMat كما هو مطلوب. لاحظ أن auto_ptr وscoped_ptr هي الطبقات أخف كثيرا لم يكن لديك وظيفة لdeleters العرف، ولكن إذا كنت على استعداد للأحمال صغيرة ثم shared_ptr يمكن استخدامها في مكانها.

إذا كان كل ما يهمك هو السلامة الاستثنائية، فافعل ذلك في كل مرة تستخدم فيها المصفوفات:

void f() {
    try {
        CvMat* mat = cvCreateMat(320, 240, CV_32FC3));
        // ...
    } catch(...) {
        cvReleaseMat(mat);
        throw;
    }
    cvReleaseMat(mat);
}

إذا، من ناحية أخرى، تريد عاقل الحل، اذهب إلى أبعد من ذلك واكتب غلافًا كاملاً.

namespace cv {

class Mat {
public:
    enum Type { /* ... */ };
    Mat(int w, int h, Type type) {
        impl = cvCreateMat(w, h, intFromType(type));
    }

    ~Mat() {
        cvReleaseMat(impl);
    }

    void pow() { // wrap all operations
        cvPow(impl);
    }

private:
    CvMat* impl;
};

}

إن اتباع الطريق الأوسط، باستخدام مجموعة من المؤشرات الذكية العامة و"cv_ptrs"، يبدو وكأنه وصفة للصداع والتعقيدات غير الضرورية.

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