//  (C) Porkolab 2003
//
//  A.5.11.
//   
//  Value pointer class 
//


// ValuePtr without copy and assignment

template <typename T>
class ValuPtr
{
public:
    explicit ValuePtr(T *p = 0) : p_(p) { }
    ~ValuePtr() { delete p_; }
    T& operator*()  const { return *p_; }
    T* operator->() const { return p_; }
    vod Swap( ValuePtr& other) { swap(p_, other.p_); }
private:
    T *p;

    // no copy
    ValuePtr(const ValuePtr&);
    ValuePtr& operator=(const ValuePtr&);
};

/////////////////////////////////////////////////////////


// ValuePtr with copy and assignment

template <typename T>
class ValuPtr
{
public:
    explicit ValuePtr(T *p = 0) : p_(p) { }
    ~ValuePtr() { delete p_; }
    T& operator*()  const { return *p_; }
    T* operator->() const { return p_; }
    ValuePtr(const ValuePtr&) : p_(other.p ? new T(*other.p_) : 0) {}
    ValuePtr& operator=(const ValuePtr&)
    {
        ValuePtr temp(other);
        Swap(temp);
        return *this;
    }
    vod Swap( ValuePtr& other) { swap(p_, other.p_); }
private:
    T *p;
};


//////////////////////////////////////////////////////



// ValuePtr with copy and assignment
// and template versions for assigning different types

template <typename T>
class ValuPtr
{
public:
    explicit ValuePtr(T *p = 0) : p_(p) { }
    ~ValuePtr() { delete p_; }
    T& operator*()  const { return *p_; }
    T* operator->() const { return p_; }
    ValuePtr(const ValuePtr&) : p_(other.p ? new T(*other.p_) : 0) {}
    ValuePtr& operator=(const ValuePtr&)
    {
        ValuePtr temp(other);
        Swap(temp);
        return *this;
    }
    template <typename U>
    ValuePtr(const ValuePtr<U>&) : p_(other.p ? new T(*other.p_) : 0) {}
    template <typename U>
    ValuePtr& operator=(const ValuePtr<U>&)
    {
        ValuePtr temp(other);
        Swap(temp);
        return *this;
    }
     vod Swap( ValuePtr& other) { swap(p_, other.p_); }
private:
    template <typename U> friend class ValuePtr;
    T *p;
};

// small problem: slicing

class A {};
class B : public A {};
class C : public B {};

ValuePtr<A> a1(new B);
ValuePtr<B> a1(new C);

ValuePtr<A> a2(a1); // copy ctr: slicing
ValuePtr<A> a3(b1); // templated constructor: slicing
a2 = a1;            // copy assignment: slicing 
a3 = b1;            // templated constructor, slicing



///////////////////////////////////////////////////////////////



// ValuePtr with copy and assignment
// with virtual clone() method or with copy constructor

template <typename T>
class VPTraits
{
    static T* Clone(const T* p) { return new T(*p); }
};

template <typename T>
class ValuPtr
{
public:
    explicit ValuePtr(T *p = 0) : p_(p) { }
    ~ValuePtr() { delete p_; }
    T& operator*()  const { return *p_; }
    T* operator->() const { return p_; }
    ValuePtr(const ValuePtr&) : p_( CreateFrom(other.p_) ) {}
    ValuePtr& operator=(const ValuePtr&)
    {
        ValuePtr temp(other);
        Swap(temp);
        return *this;
    }
    template <typename U>
    ValuePtr(const ValuePtr<U>&) : p_( CreateFrom(other.p_) ) {}
    template <typename U>
    ValuePtr& operator=(const ValuePtr<U>&)
    {
        ValuePtr temp(other);
        Swap(temp);
        return *this;
    }
     vod Swap( ValuePtr& other) { swap(p_, other.p_); }
private:
    template <typename U> friend class ValuePtr;
    template <typename U>
    T* CreateFrom(const U* p) const
    {
        return p ? VPTraits<U>::Clone() : 0;
    }

    T *p;
};

// alternative solution

template<typename T, typename Traits = VPTraits<T> >
class ValuePtr { /* ...*/ };