Deep Copyを行うポインタ

深いコピーを行うポインタ。
使うかどうか分かんないけど、参考にしたソースの通り、pimplには使えるかも。

深いコピーに合わせて深い比較(deep comparison)も行います。
型はCopyConstructibleで。

完全型云々辺りはよく分からないのでもう少し調べてみよう。

Custom Deleterには未対応。

deep_copy_ptr.hpp

// Deep copy/compare Pointer

#ifndef HWM_DEEPCOPYPTR_HPP_
#define HWM_DEEPCOPYPTR_HPP_

#include <memory>
#include <boost/assert.hpp>
#include <boost/noncopyable.hpp>

namespace hwm {

namespace detail {

class deep_copy_ptr_holder_base
    :    boost::noncopyable
{
public:
    virtual ~deep_copy_ptr_holder_base    () {}
    virtual std::auto_ptr<deep_copy_ptr_holder_base>
                        clone            () const = 0;
    virtual void*        get_ptr            () = 0;
    virtual const void* get_ptr            () const = 0;
};


template <class T>
class deep_copy_ptr_holder
    :    public deep_copy_ptr_holder_base
{
    typedef deep_copy_ptr_holder         this_type;
    typedef deep_copy_ptr_holder_base    base_type;
    
    std::auto_ptr<T> ptr_;
public:
    explicit this_type    (T* ptr) : ptr_(ptr) {}
    explicit this_type    (std::auto_ptr<T> p) : ptr_(p) {}

    std::auto_ptr<T>    clone_detail() const    {
        return
            (ptr_.get())
            ?    std::auto_ptr<T>( new T(*ptr_) )
            :    std::auto_ptr<T>();
    }
    
    virtual std::auto_ptr<base_type>
                        clone        () const    { return std::auto_ptr<base_type>(new this_type(clone_detail())); }

    virtual void*        get_ptr        ()            { return ptr_.get(); }
    virtual const void* get_ptr        () const    { return ptr_.get(); }
};

}    //namespace detail

template <class T>
class deep_copy_ptr
{
private:
    typedef void (deep_copy_ptr::*bool_type)() const;
    void         bool_func        () const {}
    
    std::auto_ptr<detail::deep_copy_ptr_holder_base> holder_;

public:
    deep_copy_ptr                () : holder_(new detail::deep_copy_ptr_holder<T>(0)) {}
    template<typename Y>
    explicit     deep_copy_ptr    (Y* p) : holder_(new detail::deep_copy_ptr_holder<T>(std::auto_ptr<T>(p)))    {}
    template<typename Y>
    explicit     deep_copy_ptr    (std::auto_ptr<Y> p) : holder_(new detail::deep_copy_ptr_holder<T>(p))        {}

    deep_copy_ptr                (const deep_copy_ptr& rhs) : holder_(rhs.holder_->clone()) {}

    template<typename Y>
    explicit     deep_copy_ptr    (const deep_copy_ptr<Y>& rhs) : holder_(rhs.holder_->clone()) {}

    deep_copy_ptr &    operator =     (const deep_copy_ptr& rhs) {
        BOOST_ASSERT(rhs.holder_.get());
        deep_copy_ptr<T> tmp(rhs);
        this->swap(tmp);
        return *this;
    }

    void        swap            (deep_copy_ptr &rhs) {
        std::swap(holder_, rhs.holder_);
    }

    operator    bool_type        () const {
        BOOST_ASSERT(holder_.get());
        return (holder_->get_ptr()) ? &deep_copy_ptr::bool_func : 0;
    }

    template<typename Y>
    void        reset            (Y* p = 0) {
        deep_copy_ptr tmp(p);
        swap(tmp);
    }

    T *            get                ()            {
        BOOST_ASSERT(holder_.get());
        return static_cast<T *>(holder_->get_ptr());
    }
    
    T    const *    get                () const    {
        BOOST_ASSERT(holder_.get());
        return static_cast<T const *>(holder_->get_ptr());
    }
    
    T *            operator ->        ()            { return get(); }
    T    const *    operator ->        () const    { return get(); }
    T &            operator *        ()            { return *get(); }
    T    const &    operator *        () const    { return *get(); }

    template<typename Y>
    bool        operator==        (Y const *p) const {
        BOOST_ASSERT(holder_.get());
        return
            (get() == p) ||
            (
                (get() && p)
                ?     *get() == *p
                :     false );
    }

    template<typename Y>
    bool        operator!=        (Y const *p) const { return !((*this) == p); }

    template<typename Y>
    bool        operator==        (deep_copy_ptr<Y> const &r) const { return (*this) == r.get(); }

    template<typename Y>
    bool        operator!=        (deep_copy_ptr<Y> const &r) const { return (*this) != r.get(); }
};

template<typename T>
void swap(deep_copy_ptr<T> &lhs, deep_copy_ptr<T> &rhs)
{
    lhs.swap(rhs);
}

template<typename T, typename U>
bool operator==(T const *t, deep_copy_ptr<U> const &u) { return u == t; }

template<typename T, typename U>
bool operator!=(T const *t, deep_copy_ptr<U> const &u) { return u != t; }

}    //namespace hwm

#endif    //HWM_DEEPCOPYPTR_HPP_

テスト

#include <iostream>
#include <string>
#include <boost/test/minimal.hpp>
#include <boost/current_function.hpp>

#include "deep_copy_ptr.hpp"

struct A
{
    int     i;
    char    c;

    A()
    :    i(0)
    ,    c(0)
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }

    A(A const &a)
    :    i(a.i)
    ,    c(a.c)
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }

    A& operator= (A const &a)
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
        i = a.i;
        c = a.c;

        return *this;
    }

    virtual void foo() = 0;
};

struct B
    :    public A
{
    std::string s;

    B()
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }

    B(B const &b)
    :    A(b)
    ,    s(b.s)
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }

    B& operator= (B const &b)
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
        static_cast<A &>(*this) = static_cast<A const &>(b);
        s = b.s;
        return *this
    }

    bool operator==(B const &b) const
    {
        return
            i == b.i &&
            c == b.c &&
            s == b.s;
    }

    void foo() {}
};

struct C
{
    B    b;

    C()
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }

    C(C const &c)
    :    b(c.b)
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }

    C& operator= (C const &c)
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
        b = c.b;

        return *this;
    }
};

struct D
{
    hwm::deep_copy_ptr<C>    c;

    D() : c(new C)
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }

    D(D const &d)
    :    c(new C(*d.c))
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }

    D& operator=(D const &d)
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
        c = d.c;
        return *this;
    }
};

class E
{
public:
    hwm::deep_copy_ptr<D> d;
    E()
    :    d(new D())
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }

    ~E()
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }

    E(E const &e)
    :    d(new D(*e.d))
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
    }

    E& operator=(E const &e)
    {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
        d = e.d;
        return *this;
    }

    void bar(D const &new_d)
    {
        hwm::deep_copy_ptr<D> tmp(new D(new_d));
        swap(d, tmp);
    }
};

int test_main(int argc, char **argv)
{
    D    d1;
    d1.c->b.s = "test";
    d1.c->b.i = 100;
    d1.c->b.c = 'X';

    D    d2 = d1;
    d2.c->b.c = 'Y';
    BOOST_CHECK(d1.c->b.s == d2.c->b.s);
    BOOST_CHECK(d1.c->b.i == d2.c->b.i);
    BOOST_CHECK(d1.c->b.c != d2.c->b.c);

    E e1;
    E e2;
    e1.bar( d1 );
    e2 = e1;
    BOOST_CHECK(e1.d->c->b.s == e2.d->c->b.s);

    hwm::deep_copy_ptr<D>    d3(new D);
    BOOST_CHECK(d3);
    hwm::deep_copy_ptr<D> d4 = d3;
    BOOST_CHECK(d4);
    hwm::deep_copy_ptr<D>().swap(d4);
    BOOST_CHECK(!d4);    
    BOOST_CHECK(d4 == false);
    BOOST_CHECK(d4 == NULL);

    //hwm::deep_copy_ptr<A> a;        //compilation error
    hwm::deep_copy_ptr<B> b1;
    hwm::deep_copy_ptr<B> b2(new B);
    hwm::deep_copy_ptr<B> b3(new B);
    hwm::deep_copy_ptr<C> c(new C);

    BOOST_CHECK(b1 != b2);
    
    //deep comparison
    BOOST_CHECK(b2 == b3);
    //b2 == c;                         //complation error ;-)

    return 0;
}

参考 :
The Safe Bool Idiom
http://zakio.net/blog/2009/04/15-222117.html

使う・・・かなぁ?