9.3.1 OwnVector Container
Complete:
Detailed Review status
Contents
Introduction
In some cases, it may be necessary to store a collection
of objects belonging to different class types inheriting
from a common base class. Such a type of collection is
called
polymorphic. Storing polymorphic objects can't
be done just using:
where
T
is the base class type. This is because once the
std::vector<T *>
is inserted in the event,
the event takes ownership of the
container, but not of the objects; the objects are thus not destroyed
automatically when the collection is destroyed.
A container that would automatically destroy the
polymorphic objects is a
boost::ptr_vector<T>
,
but its persistent capabilities with the
EDM have not
been proven.
In order to destroy automatically contained objects when the event
is destroyed, a specific generic container template has been designed, OwnVector:
Where
T
is the base class type,
P
is the
clone policy. OwnVector is
described below.
OwnVector Interface
The
OwnVector
interface is very similar to the
std::vector
interface. In order to insert a new object in the container, the pointer has to be passed
to the
push_back
function:
edm::OwnVector<MyBaseType> v;
v.push_back( new MyConcreteType1( ... ) );
v.push_back( new MyConcreteType2( ... ) );
Where
MyConcreteType1
and
MyConcreteType2
are two concrete
class types that inherit from the base class
MyBaseType
.
Please, note that
v takes ownership of the passed objects.
So, the passed pointer can't be used after
push_back is called.
For instance the following assertion will pass:
edm::OwnVector<MyBaseType> v;
std::unique_ptr<MyBaseType> obj = std::make_unique<MyConcreteType1>( ... );
v.push_back( std::move(obj) ); // o is set to zero here
assert( obj == 0 );
In the future, we will migrate to the use of
std::unique_ptr to make
this policy more explicit in the code.
One important difference with
std::vector is that, as for
boost::ptr_vector<T>
, some
of the
STL
algorithms can't be used on poymorphic containers.
Below is a sentence taken from boost documentation:
- "Unfortunately it is not possible to use pointer containers with mutating algorithms from the standard library"
In particular, the most used algorithm,
sort
, has been implemented, as for
boost::ptr_vector<T>
,
as a member function. So, the following code can be used to sort an
OwnVector
:
edm::OwnVector<MyBaseType> v;
v.push_back( new MyConcreteType1( ... ) );
v.push_back( new MyConcreteType2( ... ) );
// . . .
// sort using uses the < operator between
// two objects of type MyBaseType
v.sort();
// uses a custom comparator object
v.sort( MyComparator() );
Clone Policies and OwnVector
In order to clone an
OwnVector
, the correct
policy for
cloning the contained objects has to be specified. This is done using
a second template parameter type in
OwnVector
.
By defalult, the policy is
ClonePolicy
,
which calls a method called
clone()
, which is assumed to be
defined (in most cases purely virtual) in the base class.
It is possible to use any user-defined clone policy by implementing
the follwing interface:
static T * clone( const T & t );
where
T
is the base class type.
Generating OwnVector Dictionaries
In order to create a dictionary to insert
OwnVectors
objects in
the event, the following guidelines should be followed:
- the base class and all subclass types should be added to the dictionary
-
std::vector<MyBaseType *>
, the underlying container should be added
-
edm::OwnVector<MyBaseType>
should be added
-
edm::Wrapper<edm::OwnVector<MyBaseType> >
- if the type
MyBaseType
does not support the " <
" operator, the sort()
function should be excluded from the dictionary generation
- in order to allow automatic loading of the shared libraries contaning the concrete subtypes, it may be necessary to add the dictionaries of the concrete types, like:
edm::Wrapper<MyConcreteType1>
. This is the case if the concrete types' dictionaries (MyConcreteType1
, MyConcreteType2
, ...) are contained in a separate library w.r.t. the base type (MyBaseType
).
An example of dictionary generation is the following:
<lcgdict>
<selection>
<class name="MyBaseType" />
<class name="MyConcreteType1" />
<class name="MyConcreteType2" />
. . .
<class name="edm::OwnVector<reco::MyBaseType, edm::ClonePolicy<reco::MyBaseType> >" />
<class name="edm::Wrapper<edm::OwnVector<reco::MyBaseType,
edm::ClonePolicy<reco::MyBaseType> > >" />
</selection>
<exclusion>
<class name="edm::OwnVector<reco::MyBaseType, edm::ClonePolicy<reco::MyBaseType> >">
<method name="sort" />
</class>
</exclusion>
</lcgdict>
Review status
Responsible:
LucaLista
Last reviewed by:
PetarMaksimovic 28 Feb 2008