From: Goran on
On Oct 7, 6:14 am, ManicQin <manic...(a)gmail.com> wrote:
> I tried to think of a way to deep copy the vector into another ->without<-
> adding Clone function and such to the objects and I couldnt
> think of one, I would be happy if anyone knows of a way...

What's not great with your idea is that you get deep or shallow copy
depending on whether Interface "implements" ICloneable or not, which
might end up in a surprise for the user. But hey, it's simple and will
work with that small constraint!

You could also add "cloning traits" template parameter to your
container. Duty of that thing would be to create a clone of your
items ;-). As default, you could use the simplest possible: copy-
construction (but, that doesn't work if Interface is abstract). You
can also offer ICloneable-using version. E.g.

template<class Interface> struct DefaultCloningTrait
{ // Default: needs "copy-constructible"
Interface* Clone(const Interface& Item) const { return new Interface
(Item); }
};

template<class Interface, class
CloningTrait=DefaultCloningTrait<Interface> >
class CompositorBase
{
CloningTrait _CloningTrait;
public:
CompositorBase(CloningTrait ct=CloningTrait()) : _CloningTrait(ct)
{};
Interface* CloneItem(const Interface& Item) { return
_CloningTrait.Clone(Item); }
};

template<class Interface> struct CloneableCloningTrait
{ // Using ICloneable interface
Interface* Clone(const Interface& Item) const { return
dynamic_cast<const ICloneable&>(Item).Clone(); }
};

Goran.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Goran on
On Oct 7, 2:45 pm, Nick Hounsome <nick.houns...(a)googlemail.com> wrote:
> In my experience developing a framework that isn't strongly grounded
> in real application requirements often leads to this sort of mess
> where the developer struggles to create something that could do
> everything but actually just constrains the users

+1 for this. Scope is king and complicated scope tends to be a bad
one.

Goran.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: ManicQin on
On Oct 7, 2:46 pm, Goran <goran.pu...(a)gmail.com> wrote:
Thanks everybody, you confirmed my fear that there is no normal way to
do a polymorphic deep copy (without Clone) and that the solution I
selected is not good.
I agree that it's better to give up the copyItem method instead of
making it a half deep.

Nick about the partial specialization in manners of design I can
easily add it but, will it work even though IClonable is an ancestor
of the current Interface?
lets take Neil Butterworth example lets say my class looks like:
template <typename T>
class C {
public:
// stuff
private:
std::vector <T*> v;

};

and I'm using the interface IRestriction that inherits from IClonable
C<IRestriction> VicTheVector;

my CopyItems should look like:
template <>
class C<IClonable>{

}

The class that I instantiate is C<IRestriction> and not C<ICLonable>
should it still work?
that was my first try but the compiler doesn't recognizes IRestriction
as IClonable...

Thanks


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Kenneth 'Bessarion' Boyd on
On Oct 6, 11:14 pm, ManicQin <manic...(a)gmail.com> wrote:
> Hi, I'll do my best to explain my problem...
> I have an data type that is wrapping a vector of pointers, currently I
> have no control of the type that the vector holds and I need to be as
> generic as I can (it's a part of a frame work).
> naturally my vector is templated by the client.
>
> I tried to think of a way to deep copy the vector into another ->without<- adding Clone function and such to the objects and I couldnt
> think of one, I would be happy if anyone knows of a way...

Aside from syntactical details: it's virtual Clone or bust for a
polymorphic-result deep copy in C++98: virtual operator= won't save
you, as it doesn't get inherited. The language in draft n2914 of C+
+0X looks like this may have been remediated.

Unfortunately, I haven't seen a good way to nonfatally compile-time
test for the declaration of a (member) function. That would, at
least, allow using a defaulted bool parameter to specialize the
proposed class based on the presence of a Clone member function.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Kian Karas on
{ Please limit your text to 70 columns or so to prevent unwanted breaks
in the middle of the lines. -mod }

#include <vector>
#include <algorithm>
using namespace std;

/*
As written in prior comments, it is a bad idea to determine the copying method
at run-time - because you can't!

I agree with Goran that what you need is a policy template argument (it is not
called traits). However, the suggested DefaultCloningTrait class is unfortunate
in that it does not support non-pointer types - std::vector does. Hence, lets
make one that support the copy-assignment idiom, which is the behavior you get
when copying a container from std
vector<int> v1;
vector<int> v2(v1);

Here is the CopyAssign policy:
*/

template<class T>
struct CopyAssign
{
static T Copy(const T& t)
{ return t; }
static void Destroy(const T&) {}
protected:
~CopyAssign() {}
};

/*
The intention is to use the policy class like this:

CopyAssign<int*> pol;
int n = 42;
int* pn = pol.Copy(n); // pn == &n

Note that Copy() is static to avoid the overhead of passing the 'this' pointer.

The presence of the Destroy() function will make sence in a moment.

Now lets look at how the CompositorBase will use the policy.
*/

template<class Element, template<class> class CreationPolicy = CopyAssign>
class CompositorBase : public CreationPolicy<Element>
{
typedef vector<Element> Container;
public:
CompositorBase() {}
CompositorBase(const CompositorBase& c) : m_cData(c.m_cData.size())
{
CreationPolicy<Element>& myPolicy = *this;
for (size_t n = 0; n < m_cData.size(); ++n) {
m_cData[n] = myPolicy.Copy(c.m_cData[n]);
}
}
~CompositorBase()
{
CreationPolicy<Element>& myPolicy = *this;
for (size_t n = 0; n < m_cData.size(); ++n) {
myPolicy.Destroy(m_cData[n]);
}
}

void PushBack(const Element& e) { m_cData.push_back(e); }
private:
Container m_cData;
};

/*
There are a few things to note:
- The policy is derived instead of being a member. It has the advantage that
it gives the compiler the possibility of making the empty base class
optimization.
- Now it is clear why the destructor of the CopyAssign policy was made
protected: it is to avoid partial deletion of CompositorBase objects. Adding
a virtual destructor would also have solved that problem, but then the size
of the poly class would no longer be zero.
- The policy template argument is a template template argument! This has the
advantage that the policy can be used inside the CompositorBase class with a
different element type.

Because we want this implementation of the CompositorBase class to support non
pointer elements, it is not possible to write a destructor that simply deletes
all elements.
Whether or not the operator delete shall be invoked on an element depends on
two properties:
- Does the CompositorBase class own the elements?
- Does the Creation Policy allocate elements on the heap?
If the answer to the first question is _no_, then the destructor shall do
nothing, else it should be implemented like above. The empty
CopyAssign::Destroy() definition now makes sence: Objects not allocated on the
heap shall not be deleted in the destructor.

Now lets add a policy which can be used to copy objects to the heap.
*/

template<class T>
struct CopyHeap;

template<class T>
struct CopyHeap<T*>
{
static T* Copy(const T* pt)
{ return new T(*pt); }
static void Destroy(const T* pt)
{ delete pt; }
protected:
~CopyHeap() {}
};

/*
The primary template does not have a definition and then it is followed by a
strange looking partial specialization. The partial specialization will be
instantiated for pointer types and the primary template in all other cases
(non-pointers). This will give you a compile-time error if trying to use the
CopyHeap policy with non-pointer types (which is what we want):

CompositorBase<int, CopyHeap> error; // Won't compile
CompositorBase<int*, CopyHeap> ok;

Note that the policy now invokes operator delete on its argument.

Another reason for using partial specialization is to obtain 'base' type
without the pointer. Else, the call to operator new T() would yield a 'pointer
to a pointer to int':
*/

template<class PointerType>
struct CopyHeapError
{
static PointerType Copy(const PointerType p)
{ return new PointerType(*p); } // Error
};

/*
Now we only need a policy for cloning objects.
*/

template<class T>
struct ClonePolicy;

template<class T>
struct ClonePolicy<T*>
{
static T* Copy(const T* pt)
{ return pt->Clone(); }
static void Destroy(const T* pt)
{ delete pt; }
protected:
~ClonePolicy() {}
};

/*
The above set of policies solve most cases, but not the case where the policy
needs to make a cross-cast to obtain the IClone interface (as shown in your
example). As there are no way of determining run-time whether or not the cross-
cast is valid, you need to determine how to handle that error. The following
implementation will throw a bad_cast exception upon error.
*/

template<class T>
struct CrossClone;

template<class T>
struct CrossClone<T*>
{
static T* Copy(const T* pt)
{
const ICloneable& t = dynamic_cast<const ICloneable&>(*pt);
return dynamic_cast<T*>(t.Clone());
}
static void Destroy(const T* pt)
{ delete pt; }
protected:
~CrossClone() {}
};

/*
Note the second dynamic_cast in the Clone() function. It is necessary to cast
the new instance from ICloneable back to the type held in the container.

It would be a waste to apply the dynamic_cast to IClonable elements. Hence, we
can make a 'full' specialization for ICloneable (I honestly don't know if any
compiler will/can optimize the dynamic_cast away - better safe than sorry):
*/

struct ICloneable;

template<>
struct CrossClone<ICloneable*>
{
static ICloneable* Copy(const ICloneable* p)
{ return p->Clone(); }
static void Destroy(const ICloneable* pt)
{ delete pt; }
protected:
~CrossClone() {}
};

/*
Remember also to either declare the CompositorBase::operator=() private or
implement it using the CreationPolicy.
Note: The suggested CompositorBase constructor is not exception safe. You will
have a memory leak if the call to Copy() throws. Luckily this problem can be
solved, but I leave that to you.

Below is some example code that will compile and use the different policies.
*/

struct ICloneable
{
virtual ~ICloneable() {}
virtual ICloneable* Clone() const = 0;
};

struct Base
{
virtual ~Base() {}
};

struct Cloneable : ICloneable, Base
{
virtual Cloneable* Clone() const { return new Cloneable(*this); }
};

int main(int argc, char* argv[])
{
typedef CompositorBase<int> IntAssign;
IntAssign intAssign;
IntAssign intAssign2(intAssign);

//CompositorBase<int, CopyHeap> intHeap; // Error: int is not a valid heap type

typedef CompositorBase<int*, CopyHeap> IntPHeap;
IntPHeap intPHeap;
IntPHeap intPHeap2(intPHeap);

typedef CompositorBase<Cloneable*, ClonePolicy> CloneablePClone;
CloneablePClone cloneablePClone;
CloneablePClone cloneablePClone2(cloneablePClone);

typedef CompositorBase<Base*, CrossClone> BasePCross;
BasePCross basePCross;
basePCross.PushBack(new Cloneable);
BasePCross basePCross2(basePCross);

typedef CompositorBase<ICloneable*, CrossClone> ICloneablePCross;
ICloneablePCross iCloneablePCross;
iCloneablePCross.PushBack(new Cloneable);
ICloneablePCross iCloneablePCross2(iCloneablePCross);

return 0;
}

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

First  |  Prev  |  Next  |  Last
Pages: 1 2 3
Prev: Help With TR1 regex_match()
Next: Is this correct C++?