Aim: This class encapsulates its parameter class to indicate that the given parameter is required to be duplicated (generally, this is done to have a longer lifetime than the function itself). On one hand, the user is reminded of the possible cost of duplicating the argument parameter, while he is also aware that the lifetime of the parameter is not a problem for the function. On the other hand, the Clone class is smart enough to enforce duplication only if needed. Substantial speed-up can be achieve through this mechanism.
More...
template<typename T>
class DGtal::Clone< T >
Aim: This class encapsulates its parameter class to indicate that the given parameter is required to be duplicated (generally, this is done to have a longer lifetime than the function itself). On one hand, the user is reminded of the possible cost of duplicating the argument parameter, while he is also aware that the lifetime of the parameter is not a problem for the function. On the other hand, the Clone class is smart enough to enforce duplication only if needed. Substantial speed-up can be achieve through this mechanism.
Description of template class 'Clone'
(For a complete description, see Parameter passing, cloning and referencing).
The class Clone is used in methods or functions to encapsulate the parameter types. The following conversion from input parameter to data member or variable are sumed up in the following table:
Argument type: | const T& | T* | CountedPtr<T> | CowPtr<T> | T&& (c++11) |
To:T | Dupl. O(N) | Acq. Dupl. O(N) | Dupl. O(N) | Dupl. O(N) | Move. O(1) |
To:T* | Dupl. O(N) | Acq. O(1) | Dupl. O(N) | Dupl. O(N) | Move. O(1) |
To:CowPtr<T> | Dupl. O(N) | Acq. O(1) | Lazy. O(1)/O(N) | Lazy. O(1)/O(N) | Move. O(1) |
with abbreviations:
- Dupl. Object is duplicated.
- Lazy. Object is lazily duplicated, meaning only when the user writes on it (which may be never).
- Acq. Dynamically allocated pointer is acquired. User should take care himself of deletion only if storing the parameter with a pointer.
- Move. The object is moved into the new object. This is generally much faster than copy. This is true for instance for all classical STL containers. You can also write a specific
move
constructor for your class.
It is clear that worst case is duplication while sometimes Clone is constant time (while guaranteeing object invariance and life-time).
- Note
- The usage of
Clone<T>
instead of const
T
&
or const
T
*
in parameters is always recommended when the user duplicates the parameter and stores a clone of it as a data member for later use. The usage Clone<T>
instead of T
is recommended whenever T
is big (the object is sometimes duplicated twice). When the object is small, writing either Clone<T>
or T
is acceptable. If your member is a CowPtr<T>, then you should use a Clone<T> as parameter. Depending on your data member, we advise the following parameter definition when duplication is asked for.
member type: | T | big T | CowPtr<T> | T* |
parameter | T or Clone<T> | Clone<T> | Clone<T> | Clone<T> |
- Note
- A conversion to
T*
means pointer acquisition. Hence the programmer should take care of deletion of the object. Otherwise, deletion is automatic for T
or CowPtr<T>
member. Furthermore, a conversion to a T*
requires the use of the address operator (operator&
) by the developer. If argument is Clone<T> a
, and member name is b
:
member type: | T | T* | CowPtr<T> |
member deletion: | automatic | manual | automatic |
conversion: | automatic: b(a) | address: b(&a) | automatic: b(a) |
- Note
- When choosing a
Clone<T>
parameter, the programmer should really consider using a CowPtr<T>
member to store it, since it is the most versatile and optimizable variant. The only advantage of the two others storing methods (T
and T*
) is that there is one less indirection.
-
Note that an instance of Clone<T> is itself a light object (it holds only a const enum and const pointer), the duplication (if necessary) takes place when the user instantiates its member of type T (or CowPtr<T> or T* member).
- Template Parameters
-
- See also
- Alias
-
ConstAlias
- Note
- (Speed) Even on a small type (here a pair<int,int>), it is much faster than NClone and has the advantage (wrt Clone<T>) to handle nicely both const T& and CowPtr<T> as input. It may be slightly slower than deprecated::Clone (and by value or by const ref parameter passing) for small objects like a pair<int,int>. This is certainly due to the fact that it uses one more integer register for myParam data member.
Type | Context | value | const ref | deprecated::Clone | Clone |
2xint | i7 2.4GHz | 48ms | 48ms | 48ms | 59ms |
2xdouble | i7 2.4GHz | 48ms | 48ms | 48ms | 49ms |
2xint | Xeon 2.67GHz | 54ms | 54ms | 54ms | 54ms |
2xdouble | Xeon 2.67GHz | 54ms | 54ms | 54ms | 53.5ms |
- Note
- It prevents direct assignment to CountedPtr<T> since their meaning is "shared_ptr".
It can be used as follows. Consider this simple example where class A is a big object. Then we define three classes B1, B2 and B3, that uses some instance of A.
const int N = 10000;
struct A { ...
int table[N];
};
struct B1 {
B1( const A & a )
: myA( a ) {}
...
const A & myA;
};
struct B2 {
B2( const A & a )
: myA( a ) {}
...
A myA;
};
struct B3 {
B3( const A & a )
{ myA = new A( a ); }
~B3()
{ if ( myA != 0 ) delete myA; }
...
A* myA;
};
Sometimes it is also very important that the developper that uses the library is conscious that an object, say b, may require that an instance a given as parameter should have a lifetime longer than b itself (case for an instance of B1 above). Classes Clone, Alias, ConstAlias exist for these reasons. The classes above may be rewritten as follows.
struct B1 {
: myA( a ) {}
...
const A & myA;
};
struct B2 {
B2( Clone<A> a )
: myA( a ) {}
...
A myA;
};
struct B3_v1 {
B3_v1( Clone<A> a )
: myA( &a ) {}
~B3_v1() { if ( myA != 0 ) delete myA; }
...
A* myA;
};
struct B3_v2 {
B3_v2( Clone<A> a )
: myA( a ) {}
~B3_v2() {}
...
CountedPtr<A> myA;
};
struct B3_v3 {
B3_v3( Clone<A> a )
: myA( a ) {}
~B3_v3() {}
...
CowPtr<A> myA;
};
...
A a1;
B1 b( a1 );
B2 bb( a1 );
B2 bbb( &a1 );
B3_v1 c1( a1 );
B3_v2 c1( a1 );
B3_v3 c1( a1 );
Aim: This class encapsulates its parameter class so that to indicate to the user that the object/poin...
A last question could be why are we not just passing the instance of A by value. This, for sure, would tell the developper that the instance is duplicated somehow. The problem is that it induces generally two duplications, and not only one ! It may be possible that the compiler optimizes things nicely but it is unclear if the compiler will always do it. Furthermore, sometimes, no duplication is needed (when duplicating a CowPtr for instance).
struct B4 {
B4( A a )
: myA( a ) {}
...
A myA;
};
A a1;
B4 b4( a1 )
- Note
- The user should not used Clone<T> for data members, only as a type for parameters.
Definition at line 266 of file Clone.h.