与在C写的图书馆的聪明的指针 [英] Smart pointers with a library written in C

查看:93
本文介绍了与在C写的图书馆的聪明的指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用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类I已经做了。我将它重命名为 cv_ptr 然后使用智能指针,如: std :: auto_ptr< cv_ptr> 。这个烦人的事情是,我总是要dereference两次:

  std :: auto_ptr< cv_ptr>矩阵(cv_ptr(cvCreateMat(320,240,CV_32FC3))); 
cvPow(matrix.get() - > get()); //一个为auto_ptr,一个为cv_ptr

我知道它看起来像我可以声明一个隐式转换,但我实际上不能 - 大多数OpenCV的函数都有参数void * - 所以不会调用隐式转换。



第二,我可以在某种程度上覆盖 operator delete 。我不想覆盖全局操作符删除,因为我只想要应用于CvMat(和其他几个)类型。但是,我不能更改库,所以我不能添加 operator delete 到CvMat结构。

第三,我可以重写我自己的 auto_ptr code>, scoped_ptr shared_ptr 。他们不是大课,所以它不会太难,但我只是觉得这是不好的设计。如果我这样做,我可能会这样做:

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

//每个方法只是一个智能指针的代理
CvMat * get(){return this-> matrix_.get() - > get() }
// auto_ptr中的所有其他运算符/方法都是一样的,你得到的想法

private:
auto_ptr< cv_ptr>矩阵_; // cv_ptr正确删除CvMat
}

解决方案

auto_ptr真的是为C ++类的RAII设计的,你正在推送的构造/析构函数他们在这里使用的东西,他们可能不应该使用(但可以)。



无论如何,你想要能够使用你的C ++对象,因为它是一个正常的堆栈变量,而不是每次动态分配?



您的问题的标准解决方案是创建一个包含构造函数/析构函数的包装。

但是为了使它可以被C函数使用,只需要添加一个内部的cast操作符 - 传递给C函数时,将其自身转换回C对象。



编写一个包装类。

 类Mat 
{
CvMat * impl;
public:
Mat(/ * Constructor Arguments * /)
{
impl = cvCreateMat(/ * BLAH * /);
}
〜Mat()
{
cvReleaseMat(impl);
}
operator CvMat *()
{// Cast操作符。将您的C ++包装器对象转换为C对象
//当它与
//库中的所有C函数一起使用时。

return impl;
}
};

void Plop(CvMat * x)
{//处理CvMat的一些C函数
}

int main()
{ //不需要动态分配
Mat m; //只是在堆栈上创建。
Plop(m); //直接调用Plop

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


I'm using C++ with the OpenCV library, which is a library image-processing although that's not relevant for this question. Currently I have a design decision to make.

OpenCV, being a C library, has its data structures (such as CvMat) declared as structs. To create them, you use functions like cvCreateMat, and to release them, you use functions like cvReleaseMat. Being a C++ programmer, I created a special cv_scoped class which would automatically call cvReleaseMat when it went out of scope (like boost::scoped_ptr).

What I'm realising now is that I wish I could use auto_ptr and shared_ptr in cases as well. I just feel that writing code for my own cv_auto_ptr and cv_shared_ptr classes would be a bad idea, not to mention a waste of time. So I've been looking for solutions, and I've come up with three possibilities.

First, I could use the cv_scoped class I've already made. I'd rename it to cv_ptr and then use smart pointers like so: std::auto_ptr<cv_ptr>. The annoying thing about this though is, I'd always have to dereference twice:

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

I know it looks like I could declare an implicit conversion, but I couldn't actually - most of OpenCV's functions have the parameter void* - so no implicit conversion would be called. I would really like a way of doing this where I didn't have to do the double dereference.

Second, I could somehow override operator delete. I don't want to override the global operator delete because I'd only want this to apply to CvMat (and a few other) types. However, I can't change the library, so I can't add operator delete to the CvMat struct. So I don't know how this would work.

Third, I could just rewrite my own auto_ptr, scoped_ptr, and shared_ptr. They're not large classes so it wouldn't be too difficult, but I just feel like this is bad design. If I were to do this, I would probably do something along these lines:

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
}

What would you do in my situation? Please help me figure this one out.

解决方案

The auto_ptr are really designed for RAII on C++ class with constructs/destructors you are pushing their uses here to things they probably should not be used for (but can).

Anyway don'y you want to be able to use your C++ object as if it was a normal stack variable without dynamically allocating each time?

The standard solution to your problem is to create a wrapper with constructor/destructor.
But to make it usable by the C functions just add an internal cast operator so it auto-magically converts itself back to the C object when passed to a C function

Write a wrapper class.

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);
}

这篇关于与在C写的图书馆的聪明的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆