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.
If all you care about is exception safety, do this everytime you use matrixes:
If, on the other hand, you want a sane solution, go the extra mile and write a full wrapper.
Going the middle way, using a hodge podge of generic smart pointers and "cv_ptrs" sounds like a recipe for headaches and an unnecessary complication.
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.
One approach that you could consider is to used the fact that
std::tr1::shared_ptr
has the functionality to provide a custom deleter. I have no familiarity with OpenCV so I'm inferring from what you've written.Because the deleter is store in the shared pointer you can just use it as normal and when the shared raw pointer finally needs to be deleted,
cvReleaseMat
will be called as required. Note thatauto_ptr
andscoped_ptr
are much lighter classes so don't have the functionality for custom deleters, but if you're prepared for the small overhead thenshared_ptr
can be used in their place.