代码之家  ›  专栏  ›  技术社区  ›  Ray Hidayat

带有用C编写的库的智能指针

  •  3
  • Ray Hidayat  · 技术社区  · 17 年前

    我正在使用C++和OpenCV库,这是一个库图像处理,尽管这与这个问题无关。目前,我有一个设计决定要做。

    OpenCV是一个C库,它的数据结构(如CvMat)被声明为结构。要创建它们,您可以使用cvCreateMat等函数,要释放它们,可以使用cvReleaseMat等函数。作为一名C++程序员,我创建了一个特殊的 cv_scoped boost::scoped_ptr ).

    我现在意识到,我希望我能用 auto_ptr shared_ptr 在某些情况下也是如此。我只是觉得为自己写代码 cv_auto_ptr cv_shared_ptr 上课是个坏主意,更不用说浪费时间了。所以我一直在寻找解决方案,我提出了三种可能性。

    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 。我不想覆盖全局运算符delete,因为我只想将其应用于CvMat(和其他一些)类型。但是,我无法更改库,因此无法添加 运算符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
    }
    

    在我的情况下,你会怎么做?请帮我弄清楚这个。

    3 回复  |  直到 17 年前
        1
  •  6
  •   CB Bailey    17 年前

    你可以考虑的一种方法是使用以下事实 std::tr1::shared_ptr

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

    cvReleaseMat auto_ptr scoped_ptr 这些类要轻得多,所以没有自定义删除器的功能,但如果你准备好了小开销,那么 shared_ptr 可以用在他们的地方。

        2
  •  4
  •   Loki Astari    17 年前

    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
  •  3
  •   Iraimbilanja Iraimbilanja    17 年前

    如果你只关心异常安全,那么每次使用矩阵时都要这样做:

    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”的大杂烩听起来像是头痛和不必要的并发症。