Rewrote the documentation for Ptr to fit the new implementation.
authorRoman Donchenko <roman.donchenko@itseez.com>
Thu, 15 Aug 2013 10:44:25 +0000 (14:44 +0400)
committerRoman Donchenko <roman.donchenko@itseez.com>
Thu, 5 Sep 2013 15:03:00 +0000 (19:03 +0400)
modules/core/doc/basic_structures.rst
modules/core/doc/intro.rst

index b1cf053..93e7ca4 100644 (file)
@@ -710,187 +710,328 @@ train descriptor index, train image index, and distance between descriptors. ::
     };
 
 
-
-.. _Ptr:
-
 Ptr
 ---
 .. ocv:class:: Ptr
 
-Template class for smart reference-counting pointers ::
+Template class for smart pointers with shared ownership. ::
 
-    template<typename _Tp> class Ptr
+    template<typename T>
+    struct Ptr
     {
-    public:
-        // default constructor
+        typedef T element_type;
+
         Ptr();
-        // constructor that wraps the object pointer
-        Ptr(_Tp* _obj);
-        // destructor: calls release()
+
+        template<typename Y>
+        explicit Ptr(Y* p);
+        template<typename Y, typename D>
+        Ptr(Y* p, D d);
+
+        Ptr(const Ptr& o);
+        template<typename Y>
+        Ptr(const Ptr<Y>& o);
+        template<typename Y>
+        Ptr(const Ptr<Y>& o, T* p);
+
         ~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
+
+        Ptr& operator = (const Ptr& o);
+        template<typename Y>
+        Ptr& operator = (const Ptr<Y>& o);
+
         void release();
-        // user-specified custom object deletion operation.
-        // by default, "delete obj;" is called
-        void delete_obj();
-        // returns true if obj == 0;
+
+        template<typename Y>
+        void reset(Y* p);
+        template<typename Y, typename D>
+        void reset(Y* p, D d);
+
+        void swap(Ptr& o);
+
+        T* get() const;
+
+        T& operator * () const;
+        T* operator -> () const;
+        operator T* () const;
+
         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;
+        template<typename Y>
+        Ptr<Y> staticCast() const;
+        template<typename Y>
+        Ptr<Y> constCast() const;
+        template<typename Y>
+        Ptr<Y> dynamicCast() const;
     };
 
 
-The ``Ptr<_Tp>`` class is a template class that wraps pointers of the corresponding type. It is
-similar to ``shared_ptr`` that is part of the Boost library
-(http://www.boost.org/doc/libs/1_40_0/libs/smart_ptr/shared_ptr.htm) and also part of the
-`C++0x <http://en.wikipedia.org/wiki/C++0x>`_ standard.
+A ``Ptr<T>`` pretends to be a pointer to an object of type T.
+Unlike an ordinary pointer, however, the object will be automatically
+cleaned up once all ``Ptr`` instances pointing to it are destroyed.
+
+``Ptr`` is similar to ``boost::shared_ptr`` that is part of the Boost library
+(http://www.boost.org/doc/libs/release/libs/smart_ptr/shared_ptr.htm)
+and ``std::shared_ptr`` from the `C++11 <http://en.wikipedia.org/wiki/C++11>`_ standard.
 
-This class provides the following options:
+This class provides the following advantages:
 
 *
     Default constructor, copy constructor, and assignment operator for an arbitrary C++ class
-    or C structure. For some objects, like files, windows, mutexes, sockets, and others, a copy
+    or C structure. For some objects, like files, windows, mutexes, sockets, and others, a copy
     constructor or an 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 be written in C.
-    However, copy constructors and default constructors can simplify programming a lot.Besides,
-    they are often required (for example, by STL containers). By wrapping a pointer to such a
-    complex object ``TObj`` to ``Ptr<TObj>``, you automatically get all of the necessary
+    However, copy constructors and default constructors can simplify programming a lot. Besides,
+    they are often required (for example, by STL containers). By using a ``Ptr`` to such an
+    object instead of the object itself, you automatically get all of the necessary
     constructors and the assignment operator.
 
 *
     *O(1)* complexity of the above-mentioned operations. While some structures, like ``std::vector``,
     provide a copy constructor and an assignment operator, the operations may take a considerable
-    amount of time if the data structures are large. But if the structures are put into ``Ptr<>``,
+    amount of time if the data structures are large. But if the structures are put into a ``Ptr``,
     the overhead is small and independent of the data size.
 
 *
-    Automatic destruction, even for C structures. See the example below with ``FILE*``.
+    Automatic and customizable cleanup, 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 store only 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 then you loose the automatic memory management. Again, by using ``Ptr<base_class_t>()``
-    instead of the raw pointers, you can solve the problem.
-
-The ``Ptr`` class treats the wrapped object as a black box. The reference counter is allocated and
-managed separately. The only thing the pointer class needs to know about the object is how to
-deallocate it. This knowledge is encapsulated in the ``Ptr::delete_obj()`` method that is called when
-the reference counter becomes 0. If the object is a C++ class instance, no additional coding is
-needed, because the default implementation of this method calls ``delete obj;``. However, if the
-object is deallocated in a different way, the specialized method should be created. For example,
-if you want to wrap ``FILE``, the ``delete_obj`` may be implemented as follows: ::
-
-    template<> inline void Ptr<FILE>::delete_obj()
-    {
-        fclose(obj); // no need to clear the pointer afterwards,
-                     // it is done externally.
-    }
-    ...
-
-    // now use it:
-    Ptr<FILE> f(fopen("myfile.txt", "r"));
-    if(f.empty())
-        throw ...;
+    of different types in the same container is to store pointers to the base class (``Base*``)
+    instead but then you lose the automatic memory management. Again, by using ``Ptr<Base>``
+    instead of raw pointers, you can solve the problem.
+
+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 :ocv:func:`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.
+
+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.
+
+However, if the pointer must be deleted in a different way, you must specify a custom deleter upon
+``Ptr`` construction. A deleter is simply a callable object that accepts the pointer as its sole argument.
+For example, if you want to wrap ``FILE``, you may do so as follows::
+
+    Ptr<FILE> f(fopen("myfile.txt", "w"), fclose);
+    if(!f) throw ...;
     fprintf(f, ....);
     ...
-    // the file will be closed automatically by the Ptr<FILE> destructor.
+    // the file will be closed automatically by f's destructor.
 
+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::
 
-.. note:: The reference increment/decrement operations are implemented as atomic operations,
-          and therefore it is normally safe to use the classes in multi-threaded applications.
-          The same is true for :ocv:class:`Mat` and other C++ OpenCV classes that operate on
-          the reference counters.
+    namespace cv {
+    template<> void DefaultDeleter<FILE>::operator ()(FILE * obj) const
+    {
+        fclose(obj);
+    }
+    }
 
-Ptr::Ptr
---------
-Various Ptr constructors.
+For convenience, the following types from the OpenCV C API already have such a specialization
+that calls the appropriate release function:
+
+* ``CvCapture``
+* :ocv:struct:`CvDTreeSplit`
+* :ocv:struct:`CvFileStorage`
+* ``CvHaarClassifierCascade``
+* :ocv:struct:`CvMat`
+* :ocv:struct:`CvMatND`
+* :ocv:struct:`CvMemStorage`
+* :ocv:struct:`CvSparseMat`
+* ``CvVideoWriter``
+* :ocv:struct:`IplImage`
+
+.. note:: The shared ownership mechanism is implemented with reference counting. As such,
+          cyclic ownership (e.g. when object ``a`` contains a ``Ptr`` to object ``b``, which
+          contains a ``Ptr`` to object ``a``) will lead to all involved objects never being
+          cleaned up. Avoid such situations.
+
+.. note:: It is safe to concurrently read (but not write) a ``Ptr`` instance from multiple threads
+          and therefore it is normally safe to use it in multi-threaded applications.
+          The same is true for :ocv:class:`Mat` and other C++ OpenCV classes that use internal
+          reference counts.
+
+Ptr::Ptr (null)
+------------------
 
 .. ocv:function:: Ptr::Ptr()
-.. ocv:function:: Ptr::Ptr(_Tp* _obj)
-.. ocv:function:: Ptr::Ptr(const Ptr& ptr)
 
-    :param _obj: Object for copy.
-    :param ptr: Object for copy.
+    The default constructor creates a null ``Ptr`` - one that owns and stores a null pointer.
+
+Ptr::Ptr (assuming ownership)
+-----------------------------
+
+.. ocv:function:: template<typename Y> Ptr::Ptr(Y* p)
+.. ocv:function:: template<typename Y, typename D> Ptr::Ptr(Y* p, D d)
+
+    :param d: Deleter to use for the owned pointer.
+    :param p: Pointer to own.
+
+    If ``p`` is null, these are equivalent to the default constructor.
+
+    Otherwise, these constructors assume ownership of ``p`` - that is, the created ``Ptr`` owns
+    and stores ``p`` and assumes it is the sole owner of it. Don't use them if ``p`` is already
+    owned by another ``Ptr``, or else ``p`` will get deleted twice.
+
+    With the first constructor, ``DefaultDeleter<Y>()`` becomes the associated deleter (so ``p``
+    will eventually be deleted with the standard ``delete`` operator). ``Y`` must be a complete
+    type at the point of invocation.
+
+    With the second constructor, ``d`` becomes the associated deleter.
+
+    ``Y*`` must be convertible to ``T*``.
+
+    .. note:: It is often easier to use :ocv:func:`makePtr` instead.
+
+Ptr::Ptr (sharing ownership)
+----------------------------
+
+.. ocv:function:: Ptr::Ptr(const Ptr& o)
+.. ocv:function:: template<typename Y> Ptr::Ptr(const Ptr<Y>& o)
+.. ocv:function:: template<typename Y> Ptr::Ptr(const Ptr<Y>& o, T* p)
+
+    :param o: ``Ptr`` to share ownership with.
+    :param p: Pointer to store.
+
+    These constructors create a ``Ptr`` that shares ownership with another ``Ptr`` - that is,
+    own the same pointer as ``o``.
+
+    With the first two, the same pointer is stored, as well; for the second, ``Y*`` must be convertible to ``T*``.
+
+    With the third, ``p`` is stored, and ``Y`` may be any type. This constructor allows to have completely
+    unrelated owned and stored pointers, and should be used with care to avoid confusion. A relatively
+    benign use is to create a non-owning ``Ptr``, like this::
+
+        ptr = Ptr<T>(Ptr<T>(), dont_delete_me); // owns nothing; will not delete the pointer.
 
 Ptr::~Ptr
 ---------
-The Ptr destructor.
 
 .. ocv:function:: Ptr::~Ptr()
 
+    The destructor is equivalent to calling :ocv:func:`Ptr::release`.
+
 Ptr::operator =
 ----------------
-Assignment operator.
 
-.. ocv:function:: Ptr& Ptr::operator = (const Ptr& ptr)
+.. ocv:function:: Ptr& Ptr::operator = (const Ptr& o)
+.. ocv:function:: template<typename Y> Ptr& Ptr::operator = (const Ptr<Y>& o)
 
-    :param ptr: Object for assignment.
+    :param o: ``Ptr`` to share ownership with.
 
-Decrements own reference counter (with ``release()``) and increments ptr's reference counter.
-
-Ptr::addref
------------
-Increments reference counter.
+    Assignment replaces the current ``Ptr`` instance with one that owns and stores same
+    pointers as ``o`` and then destroys the old instance.
 
-.. ocv:function:: void Ptr::addref()
 
 Ptr::release
 ------------
-Decrements reference counter; when it becomes 0, ``delete_obj()`` is called.
 
 .. ocv:function:: void Ptr::release()
 
-Ptr::delete_obj
----------------
-User-specified custom object deletion operation. By default, ``delete obj;`` is called.
+    If no other ``Ptr`` instance owns the owned pointer, deletes it with the associated deleter.
+    Then sets both the owned and the stored pointers to ``NULL``.
+
+
+Ptr::reset
+----------
+
+.. ocv:function:: template<typename Y> void Ptr::reset(Y* p)
+.. ocv:function:: template<typename Y, typename D> void Ptr::reset(Y* p, D d)
+
+    :param d: Deleter to use for the owned pointer.
+    :param p: Pointer to own.
+
+    ``ptr.reset(...)`` is equivalent to ``ptr = Ptr<T>(...)``.
+
+Ptr::swap
+---------
+
+.. ocv:function:: void Ptr::swap(Ptr& o)
+
+    :param o: ``Ptr`` to swap with.
+
+    Swaps the owned and stored pointers (and deleters, if any) of this and ``o``.
+
+Ptr::get
+--------
+
+.. ocv:function:: T* Ptr::get() const
 
-.. ocv:function:: void Ptr::delete_obj()
+    Returns the stored pointer.
+
+Ptr pointer emulation
+---------------------
+
+.. ocv:function:: T& Ptr::operator * () const
+.. ocv:function:: T* Ptr::operator -> () const
+.. ocv:function:: Ptr::operator T* () const
+
+    These operators are what allows ``Ptr`` to pretend to be a pointer.
+
+    If ``ptr`` is a ``Ptr<T>``, then ``*ptr`` is equivalent to ``*ptr.get()``
+    and ``ptr->foo`` is equivalent to ``ptr.get()->foo``. In addition, ``ptr``
+    is implicitly convertible to ``T*``, and such conversion is equivalent to
+    ``ptr.get()``. As a corollary, ``if (ptr)`` is equivalent to ``if (ptr.get())``.
+    In other words, a ``Ptr`` behaves as if it was its own stored pointer.
 
 Ptr::empty
 ----------
-Returns true if obj == 0;
 
-bool empty() const;
+.. ocv:function:: bool Ptr::empty() const
 
-Ptr::operator ->
-----------------
-Provide access to the object fields and methods.
+    ``ptr.empty()`` is equivalent to ``!ptr.get()``.
 
-.. ocv:function:: template<typename _Tp> _Tp* Ptr::operator -> ()
-.. ocv:function:: template<typename _Tp> const _Tp* Ptr::operator -> () const
+Ptr casts
+---------
 
+.. ocv:function:: template<typename Y> Ptr<Y> Ptr::staticCast() const
+.. ocv:function:: template<typename Y> Ptr<Y> Ptr::constCast() const
+.. ocv:function:: template<typename Y> Ptr<Y> Ptr::dynamicCast() const
 
-Ptr::operator _Tp*
-------------------
-Returns the underlying object pointer. Thanks to the methods, the ``Ptr<_Tp>`` can be used instead
-of ``_Tp*``.
+    If ``ptr`` is a ``Ptr``, then ``ptr.fooCast<Y>()`` is equivalent to
+    ``Ptr<Y>(ptr, foo_cast<Y>(ptr.get()))``. That is, these functions create
+    a new ``Ptr`` with the same owned pointer and a cast stored pointer.
+
+Ptr global swap
+---------------
+
+.. ocv:function:: template<typename T> void swap(Ptr<T>& ptr1, Ptr<T>& ptr2)
+
+    Equivalent to ``ptr1.swap(ptr2)``. Provided to help write generic algorithms.
+
+Ptr comparisons
+---------------
+
+.. ocv:function:: template<typename T> bool operator == (const Ptr<T>& ptr1, const Ptr<T>& ptr2)
+.. ocv:function:: template<typename T> bool operator != (const Ptr<T>& ptr1, const Ptr<T>& ptr2)
+
+    Return whether ``ptr1.get()`` and ``ptr2.get()`` are equal and not equal, respectively.
+
+makePtr
+-------
+
+.. ocv:function:: template<typename T> Ptr<T> makePtr()
+.. ocv:function:: template<typename T, typename A1> Ptr<T> makePtr(const A1& a1)
+.. ocv:function:: template<typename T, typename A1, typename A2> Ptr<T> makePtr(const A1& a1, const A2& a2)
+.. ocv:function:: template<typename T, typename A1, typename A2, typename A3> Ptr<T> makePtr(const A1& a1, const A2& a2, const A3& a3)
+
+    (and so on...)
 
-.. ocv:function:: template<typename _Tp> Ptr::operator _Tp* ()
-.. ocv:function:: template<typename _Tp> Ptr::operator const _Tp*() const
+    ``makePtr<T>(...)`` is equivalent to ``Ptr<T>(new T(...))``. It is shorter than the latter, and
+    it's marginally safer than using a constructor or :ocv:func:`Ptr::reset`, since it ensures that
+    the owned pointer is new and thus not owned by any other ``Ptr`` instance.
 
+    Unfortunately, perfect forwarding is impossible to implement in C++03, and so ``makePtr`` is limited
+    to constructors of ``T`` that have up to 10 arguments, none of which are non-const references.
 
 Mat
 ---
@@ -2967,7 +3108,7 @@ Creates algorithm instance by name
 
     :param name: The algorithm name, one of the names returned by ``Algorithm::getList()``.
 
-This static method creates a new instance of the specified algorithm. If there is no such algorithm, the method will silently return null pointer (that can be checked by ``Ptr::empty()`` method). Also, you should specify the particular ``Algorithm`` subclass as ``_Tp`` (or simply ``Algorithm`` if you do not know it at that point). ::
+This static method creates a new instance of the specified algorithm. If there is no such algorithm, the method will silently return a null pointer. Also, you should specify the particular ``Algorithm`` subclass as ``_Tp`` (or simply ``Algorithm`` if you do not know it at that point). ::
 
     Ptr<BackgroundSubtractor> bgfg = Algorithm::create<BackgroundSubtractor>("BackgroundSubtractor.MOG2");
 
index 582f1d0..6d9fdfc 100644 (file)
@@ -83,17 +83,22 @@ First of all, ``std::vector``, ``Mat``, and other data structures used by the fu
     // matrix will be deallocated, since it is not referenced by anyone
     C = C.clone();
 
-You see that the use of ``Mat`` and other basic structures is simple. But what about high-level classes or even user data types created without taking automatic memory management into account? For them, OpenCV offers the ``Ptr<>`` template class that is similar to ``std::shared_ptr`` from C++ TR1. So, instead of using plain pointers::
+You see that the use of ``Mat`` and other basic structures is simple. But what about high-level classes or even user
+data types created without taking automatic memory management into account? For them, OpenCV offers the :ocv:class:`Ptr`
+template class that is similar to ``std::shared_ptr`` from C++11. So, instead of using plain pointers::
 
    T* ptr = new T(...);
 
 you can use::
 
-   Ptr<T> ptr = new T(...);
+   Ptr<T> ptr(new T(...));
 
-That is, ``Ptr<T> ptr`` encapsulates a pointer to a ``T`` instance and a reference counter associated with the pointer. See the
-:ocv:class:`Ptr`
-description for details.
+or::
+
+   Ptr<T> ptr = makePtr<T>(...);
+
+``Ptr<T>`` encapsulates a pointer to a ``T`` instance and a reference counter associated with the pointer. See the
+:ocv:class:`Ptr` description for details.
 
 .. _AutomaticAllocation: