[Insight-users] Data Representation Objects
Ofri Sadowsky
ofri@cs.jhu.edu
Thu, 21 Nov 2002 15:09:46 -0500
I added the following code in the public section of my copy of itkVectorContainer.h
<<< BEGIN >>>
/* forward declaration */
class STLVectorAdapter;
class STLConstVectorAdapter;
/** \class STLVectorAdapter
* An adapter object that casts a VectorContainer into std::vector
* and enables access to the underlying data structure. When the STLVectorAdapter
* is destroyed, it automatically calls VectorContainer::Modified().
* Here's a usage example of STLVectorAdapter
* VectorContainer::STLVectorAdapter vecAdapter =
aContainer.GetStlVectorAdapter();
* std::vector<ElementType> & vec = vecAdapter.GetStlVectorRef();
* // do things with vec ...
* // upon return from function, vecAdapter is destroyed and aContainer is
Modified()
*/
class STLVectorAdapter
{
public:
VectorType & GetStlVectorRef()
{
return (VectorType &)m_VectorRef;
}
~STLVectorAdapter()
{
m_VectorRef.Modified();
}
/** public copy ctor to enable
* VectorContainer::STLVectorAdapter vecAdapter =
aContainer.GetStlVectorAdapter();
*/
STLVectorAdapter(const STLVectorAdapter & r)
: m_VectorRef(r.m_VectorRef) {}
private:
VectorContainer & m_VectorRef;
friend class VectorContainer;
friend class STLConstVectorAdapter;
/* hide ctor */
STLVectorAdapter(VectorContainer & vc)
: m_VectorRef(vc) {}
/* hide and avoid operator= */
const STLVectorAdapter & operator=(const STLVectorAdapter & r);
};
/** Create a STLVectorAdapter that adapts this object to std::vector<ElementType>
*/
STLVectorAdapter GetStlVectorAdapter()
{
return STLVectorAdapter(*this);
}
/** \class STLConstVectorAdapter
* An adapter object that casts a VectorContainer into const std::vector
* and enables access to the underlying data structure. STLConstVectorAdapter
* does not call VectorContainer::Modified(), because it is cast to const.
* Here's a usage example of STLConstVectorAdapter
* VectorContainer::STLConstVectorAdapter vecAdapter =
* aContainer.GetConstStlVectorAdapter();
* const std::vector<ElementType> & vec = vecAdapter.GetStlConstVectorRef();
* // do things with vec ... but it can't be modified.
*/
class STLConstVectorAdapter
{
public:
const VectorType & GetStlConstVectorRef() const
{
return (const VectorType &)m_VectorRef;
}
/* no need to declare dtor, as the Adapter is const */
/* public copy ctor. See StlVectorAdapter */
STLConstVectorAdapter(const STLConstVectorAdapter & r)
: m_ConstVectorRef(r.m_ConstVectorRef) {}
/* "copy" ctor from the non-const STLVectorAdapter */
STLConstVectorAdapter(const STLVectorAdapter & r)
: m_ConstVectorRef(r.m_VectorRef) {}
private:
const VectorContainer & m_ConstVectorRef;
friend class VectorContainer;
/* hide main ctor */
STLConstVectorAdapter(const VectorContainer & vc)
: m_ConstVectorRef(vc) {}
/* hide and avoid operator= */
const STLConstVectorAdapter & operator=(const STLConstVectorAdapter & r);
};
STLConstVectorAdapter GetStlConstVectorAdapter() const
{
return STLConstVectorAdapter(*this);
}
<<< END >>>
The least I can say is that the code compiles, although I have not used it yet.
Does it look good enough to be included in the itk code? I would not like to
maintain my own version forever.
Ofri
Ofri Sadowsky wrote:
> Luis Ibanez wrote:
>
> > Hi Ofri,
> >
> > I inserted comments below...
> >
> > Ofri Sadowsky wrote:
> > > Thinking about it so far, I see two main obstacles:
> > >
> > > 1. The VectorContainer must be Modified() on every change. That means, that
> > > if we have an adapter with a public interface of std::vector that directly
> > > manipulates an underlying VectorContainer, the std::vector adapter methods
> > > have to be cleverly overloaded. Unfortunately, STL has not declared the
> > > containers methods virtual, and therefore we cannot overload them to simulate
> > > a std::vector behavior by anything else than std::vector.
> > >
> >
> > Yeap,
> > I guess that the lack of virtual methods was motivated by an
> > efficiency concern. However in principle the adapter doesn't have to
> > derive from the std::vector. It only has to provide the same interface.
> > The unfortunate thing with STL is that the "interface" has so many
> > hidden types and traits that it may be a hard work to get them all
> > right.
>
> Not necessarily so, I think. If one already has code that uses std::vector and is
> not templated, the new type, even with identicla public interface to std::vector,
> is incompatible. For example, if you defined
>
> typedef std::vector<int> MyContainerType;
>
> And then wrote a bunch of functions accepting MyContainerType, you won't be able
> to use the adapter instead.
>
> Then, about the types and traits in STL, it's not so hard a job either, I
> believe. Basically, you can copy/paste almost everything from the public header
> <vector>, and you can use the same "allocator" traits, which defines most of what
> you need. Then, you don't have to implement all the iterator mechanics and the
> rest of the stuff, just delegate them. I guess I could give such a thing a try.
>
> >
> >
> > >
> > > 2. Furthermore, it may be impossible to create a VectorContainer adapter for
> > > std::vector, as the underlying std::vector should have to report its wrapper
> > > about modifications. But std::vector does not have that capability.
> > >
> >
> > Well, the VectorContainer do not invoke "Modified" every time (also for
> > efficiency). In practice is up to the user of the class to invoke
> > Modified() whenever this is appropriate.
>
> >
> > >
> > > So it seems that creating adapters in the strong sense -- wrappers that
> > > expose a public interface of type A while delegating to internal structure of
> > > type B, should be really hard, if not impossible.
> > >
> >
> > Well, one option could be simple change the "private" derivation of the
> > Vector container for a public derivation. This will allow the
> > VectorContainer to be used in wherever a std::vector is expected.
>
> That is a very easy solution, and if it does not compromise things such as thread
> safety, it may be worthwhile. However, I would not declare the derivation
> "public", but rather provide an accessor method such as
>
> std::vector<ElementType> & VectorContainer::GetSTLVectorAdapter()
>
> So as not to over-expose the class encapsulation.
>
> >
> >
> > The other aspect (adapting a std::vector to make it look like a
> > itk::VectorContainer) will still be an open issue.
> >
> > > A very simple workaround would be to write extraction methods, that extract
> > > data from type A container object to type B container object, and vice versa.
> > > That is not "adapter", but it may still come handy at times. I could make
> > > something for that, and it should only use the currently available API, and
> > > therefore be compatible with whatever the current API is compatible with.
> > >
> >
> > Agree,
> >
> > Actually this is almost already there since we could access the
> > iterators to the underlying STL structure. After all, most STL algorithm
> > interact with the iterators of the containers rather than the containers
> > themselves.
> >
> > Luis