免费cv :: Mat没有释放内存

时间:2011-10-09 06:57:22

标签: c++ opencv

我将Mat数据(不是cv :: Mat对象)传递给函数,并使此函数成为此数据的新所有者。但是,我需要一个方法来释放原始对象,而不释放它所指向的数据缓冲区。

我知道这将发生在从外部数据创建的cv :: Mat中,我只需要将此功能用于一般的cv :: Mat。

有办法做到这一点吗?

3 个答案:

答案 0 :(得分:9)

您可以使用addref()方法,但会有内存泄漏

实际上从Mat分离数据不是一个好主意:

  • 它不是为此设计的;
  • 您不能保证从通用cv :: Mat获得的指针指向已分配内存块的开头;
  • 很可能你自己无法释放内存,因为cv :: Mat可能会使用自己的内存分配例程(有很多理由可以做到这一点,例如对齐)。
  • 即使您找到了解决数据指针所有问题的方法,您仍然无法避免Mat引用计数器的内存泄漏。

因此,只有两种方式可以保证Mat支持:

  • 在Mat创建时提供指针;
  • 将数据复制到缓冲区。

即使它在当前版本中有效,任何其他方式都可能在未来版本中被破坏。

答案 1 :(得分:3)

您可以使用lambda捕获Mat,并且可以将此lambda用作删除器,以将其生命扩展并绑定到shared_ptr / unique_ptr。

Mat matrix;
...
std::shared_ptr<uchar*> ptr(matrix.ptr(),[matrix](uchar*){});

当您不想在公共接口上使用opencv,并且无法在Mat创建时提供指针或者不想将数据复制到缓冲区时,它非常有用。

答案 2 :(得分:0)

使用发布()

PTR

http://opencv.willowgarage.com/documentation/cpp/basic_structures.html

智能引用计数指针的模板类

template<typename _Tp> class Ptr
{
public:
    // default constructor
    Ptr();
    // constructor that wraps the object pointer
    Ptr(_Tp* _obj);
    // destructor: calls release()
    ~Ptr();
    // copy constructor; increments ptr's reference counter
    Ptr(const Ptr& ptr);
    // assignment operator; decrements own reference counter
    // (with release()) and increments ptr's reference counter
    Ptr& operator = (const Ptr& ptr);
    // increments reference counter
    void addref();
    // decrements reference counter; when it becomes 0,
    // delete_obj() is called
    void release();
    // user-specified custom object deletion operation.
    // by default, "delete obj;" is called
    void delete_obj();
    // returns true if obj == 0;
    bool empty() const;

    // provide access to the object fields and methods
    _Tp* operator -> ();
    const _Tp* operator -> () const;

    // return the underlying object pointer;
    // thanks to the methods, the Ptr<_Tp> can be
    // used instead of _Tp*
    operator _Tp* ();
    operator const _Tp*() const;
protected:
    // the encapsulated object pointer
    _Tp* obj;
    // the associated reference counter
    int* refcount;
};

类Ptr&lt; _Tp&gt;是一个模板类,它包装相应类型的指针。它类似于shared_ptr,它是Boost库(http://www.boost.org/doc/libs/1_40_0/libs/smart_ptr/shared_ptr.htm)的一部分,也是C ++ 0x标准的一部分。

通过使用此类,您可以获得以下功能:

default constructor, copy constructor and assignment operator for an arbitrary C++ class or a C structure. For some objects, like files, windows, mutexes, sockets etc, copy constructor or assignment operator are difficult to define. For some other objects, like complex classifiers in OpenCV, copy constructors are absent and not easy to implement. Finally, some of complex OpenCV and your own data structures may have been written in C. However, copy constructors and default constructors can simplify programming a lot; besides, they are often required (e.g. by STL containers). By wrapping a pointer to such a complex object TObj to Ptr<TObj> you will automatically get all of the necessary constructors and the assignment operator.
all the above-mentioned operations running very fast, regardless of the data size, i.e. as “O(1)” operations. Indeed, while some structures, like std::vector provide a copy constructor and an assignment operator, the operations may take considerable time if the data structures are big. But if the structures are put into Ptr<> , the overhead becomes small and independent of the data size.
automatic destruction, even for C structures. See the example below with FILE* .
heterogeneous collections of objects. The standard STL and most other C++ and OpenCV containers can only store objects of the same type and the same size. The classical solution to store objects of different types in the same container is to store pointers to the base class base_class_t* instead, but when you loose the automatic memory management. Again, by using Ptr<base_class_t>() instead of the raw pointers, you can solve the problem.

类Ptr将包装对象视为黑盒子,引用计数器分别进行分配和管理。指针类需要知道的关于对象的唯一方法是如何释放它。这个知识在Ptr :: delete_obj()方法中被封装,当引用计数器变为0时调用该方法。如果对象是C ++类实例,则不需要额外的编码,因为此方法的默认实现调用delete obj; 。但是,如果以不同的方式释放对象,则应创建专用方法。例如,如果要包装FILE,则delete_obj可以实现如下:

模板&LT;&GT;内联void Ptr :: delete_obj() {     FCLOSE(OBJ); //之后不需要清除指针                  //它是在外部完成的。 } ...

//现在使用它: Ptr f(fopen(“myfile.txt”,“r”)); 如果(f.empty())     扔......; fprintf(f,....); ... //文件将由Ptr析构函数自动关闭。

注意:引用递增/递减操作是作为原子操作实现的,因此在多线程应用程序中使用这些类通常是安全的。 Mat和其他在参考计数器上运行的C ++ OpenCV类也是如此。