Opencv中Ptr这个类是一个智能指针
原本的用法:
//method 1 delete problem
linemod::ColorGradient cmodelity;
cmodelity = linemod::ColorGradient(30, 15, 60);
std::vector< Ptr<linemod::Modality> > modalities;//reference to the num of object to be matched
modalities.push_back(&cmodelity);
上述写法存在内存delete问题,疑似ColorGradient 存放到了modalities,智能指针没有记录引用次数,导致多次释放。
改用了
//method 2
Ptr<linemod::Modality> pmodality = new linemod::ColorGradient(30, 15, 60);
vector< Ptr<linemod::Modality>> modalities;
modalities.push_back(pmodality);
这才是正确的做法吧。
为了后续积累,翻译一下Opencv对使用这个类的说明,:
Ptr<T>伪装成目标类型T的指针。不像传统的指针,目标会被自动释放,一旦所有的指向该目标的Ptr句柄都被删除,目标会被自动清除。类似于boost::shared_ptr。
这个类提供一下好处:
- 默认构造器,拷贝构造器,赋值构造器对应任意一个C++类或者C结构体都是必要的。对于一些目标,比如文件,窗口,锁,套接字(socket)和其他,一个拷贝构造器或者一个赋值构造器是很难定义的。对于其他目标,比如复杂的分类器,拷贝构造函数是缺少的,不容易实现。最后,一些复杂的Opencv和你自己的结构体可能会用C语言写。然而,拷贝构造器和默认构造器简化编程。此外,比如,它们常常需要放在STL的容器里面。使用Ptr指向这类目标,而不是这些目标本身,你可以自动地获得所有的必要的构造器,以及赋值操作符。
- 上述操作都是*O(1)* 复杂度。当一些结构体,比如std::vector,提供了一个拷贝构造函数和赋值操作符,这些操作符的操作会花费很长的事件,如果结构体很大。但是如果结构体放入到一个Ptr中,消耗就会很小并且和数据大小无关。
- 自动自适应释放,即使是C结构体。FILE\*.example
Ptr<FILE> f(fopen("myfile.txt", "w"), fclose);
if(!f) throw ...;
fprintf(f, ....);
...
// the file will be closed automatically by f's destructor.
- 异构性收集目标( Heterogeneous collections of objects),标准的STL和大多数C++以及Opencv的容器只能够存储的单一类型和单一大小的目标。传统在同一个存储中存储不容类型的目标的方法是转而存储指向基类的指针,但是这需要自己管理内存,不能自动内存管理。在此,使用Ptr<Base>而不是原生指针,能够解决这个问题。
一个Ptr被说成是拥有一个指针,意思是,对于每一个Ptr,一个指针被释放一次,所有“拥有”该指针的Ptr句柄都会被销毁。拥有的指针可能是NULL,这种情况下没有东西会被删除。每一个Ptr也会“保存”一个指针。保存的指针是Ptr伪装成的;这个指针就是你使用Ptr::get或者传化成T*得到的指针。得到的通常和“已经拥有的”指针是一样的,但是如果你使用casts或者一般共享构造器,得到的结果会不同:Ptr仍然会拥有原始的指针,但是自己会指向其他的地方。
A Ptr is said to *own* a pointer - that is, for each Ptr there is a pointer that will be deleted
once all Ptr instances that own it are destroyed. The owned pointer may be null, in which case
nothing is deleted. Each Ptr also *stores* a pointer. The stored pointer is the pointer the Ptr
pretends to be; that is, the one you get when you use Ptr::get or the conversion to T\*. It's
usually the same as the owned pointer, but if you use casts or the general shared-ownership
constructor, the two may diverge: the Ptr will still own the original pointer, but will itself point
to something else.
拥有的指针可以看成一个黑箱子。Ptr唯一需要知道的就是怎么删除它。这部分封装在了 *deleter*中——一个辅助的目标,和拥有的指针相关联,在所有的Ptr句柄中共享。默认构造器是DefaultDeleter的句柄,DefaultDeleter使用的是标准的C++删除操作符。因此,任何有new操作符分配的指针,默认删除操作符都能够工作。
The owned pointer is treated as a black box. The only thing Ptr needs to know about it is how to
delete it. This knowledge is encapsulated in the *deleter*- an auxiliary object that is associated
with the owned pointer and shared between all Ptr instances that own it. The default deleter is an
instance of DefaultDeleter, which uses the standard C++ delete operator; as such it will work with
any pointer allocated with the standard new operator.
然而如果一个指针要以不同的方式删除,你必须在Ptr的构造过程中特别地写一个自定义删除器。一个删除器是一个简单的能够调用的目标,它能够接受指针作为它的单一参数。
@code
Ptr<FILE> f(fopen("myfile.txt", "w"), fclose);
if(!f) throw ...;
fprintf(f, ....);
...
// the file will be closed automatically by f's destructor.
@endcode
Alternatively, if you want all pointers of a particular type to be deleted the same way, you can
specialize DefaultDeleter<T>::operator() for that type, like this:
@code
namespace cv {
template<> void DefaultDeleter<FILE>::operator ()(FILE * obj) const
{
fclose(obj);
}
}
@endcode
------------------
有些地方理解不深,仅作记录,用的时候再深究。
---------------------