我正在使用C ++与OpenCV库,这是一个库图像处理,虽然这与这个问题无关。目前我有一个设计决定。
作为C库的OpenCV将其数据结构(例如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
。我不想覆盖全局运算符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
}
在我的情况下你会做什么?请帮我解决这个问题。
答案 0 :(得分: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_ptr
和scoped_ptr
是更轻松的类,因此没有自定义删除功能,但如果您已准备好承担较小的开销,则shared_ptr
可以在其位置使用
答案 1 :(得分: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);
}
答案 2 :(得分: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”听起来像是头痛和不必要的并发症的配方。