9.3.1 OwnVector Container

Complete: 5
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:

  • std::vector<T *>,
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:

  • edm::OwnVector<T, P>

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:

  1. the base class and all subclass types should be added to the dictionary
  2. std::vector<MyBaseType *>, the underlying container should be added
  3. edm::OwnVector<MyBaseType> should be added
  4. edm::Wrapper<edm::OwnVector<MyBaseType> >
  5. if the type MyBaseType does not support the " < " operator, the sort() function should be excluded from the dictionary generation
  6. 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

Reviewer/Editor and Date (copy from screen) Comments
AnneHeavey - 12 Oct 2006 copied Luca's page to workbook; minor editing
LucaLista- 11 Oct 2006 created page

Responsible: LucaLista
Last reviewed by: PetarMaksimovic 28 Feb 2008

Edit | Attach | Watch | Print version | History: r16 < r15 < r14 < r13 < r12 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r16 - 2016-09-17 - WilliamTanenbaum


ESSENTIALS

ADVANCED TOPICS


 
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    CMSPublic All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright &© 2008-2023 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
or Ideas, requests, problems regarding TWiki? use Discourse or Send feedback