2009-01-31 58 views
1

我在OpenCV庫中使用C++,這是一個庫圖像處理,雖然這與此問題無關。目前我有一個設計決定。使用C編寫的庫的智能指針

OpenCV是一個C庫,它的數據結構(如CvMat)聲明爲結構體。爲了創建它們,你使用像cvCreateMat這樣的函數,並且釋放它們,你可以使用像cvReleaseMat這樣的函數。作爲一名C++程序員,我創建了一個特殊的cv_scoped類,它會在超出範圍時自動調用cvReleaseMat(如boost::scoped_ptr)。

我現在意識到的是,我希望我也可以在案件中使用auto_ptrshared_ptr。我只是覺得爲我自己的cv_auto_ptrcv_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_ptrshared_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 
} 

你會在我的情況下做什麼?請幫我把這個弄清楚。

回答

4

auto_ptr實際上是針對C++類中的RAII而設計的,它帶有構造/析構函數,您在這裏將它們的用途推向它們可能不應用於(但可以)的東西。

無論如何,你是否希望能夠使用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); 
} 
3

如果所有你關心的是異常安全,做到這一點,每次使用矩陣:

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」聽起來就像是一個頭痛的食譜和不必要的併發症。

+0

我明白了你的觀點,但我想我可能會爲自己的智能指針而努力。我覺得因爲有很多不同的功能和類型,我覺得我正在重新改寫他們的簽名。雖然謝謝! – 2009-01-31 10:36:49

6

您可以考慮的一種方法是使用std::tr1::shared_ptr具有提供自定義刪除功能的事實。我不熟悉OpenCV,所以我從你寫的內容中推斷出來。

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

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

由於刪除器店在共享指針你可以使用它作爲正常的,當共享原始指針最終需要被刪除,因爲需要cvReleaseMat將被調用。請注意,auto_ptrscoped_ptr輕得多,因此不具備自定義刪除程序的功能,但如果您準備好了小開銷,則可以使用shared_ptr替代它們。

+0

哇,這聽起來像我所需要的,至少爲shared_ptr。謝謝! – 2009-01-31 10:25:10

+0

嗯爲什麼functor?爲什麼不直接通過cvReleaseMat作爲刪除者? – 2009-01-31 10:28:21