HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

A clone_ptr<T> that does not require T to have a clone method

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
methodclone_ptrthatrequiredoesnothaveclone

Problem

Here is my clone pointer template:

#include 
#include 
#include 

template
struct clone_ptr
{
    clone_ptr() : ptr(nullptr), cloner(nullptr) {}
    clone_ptr(clone_ptr&& other) noexcept
        : clone_ptr()
    {
        swap( other );
    }
    clone_ptr(const clone_ptr& other)
    {
        ptr = other.cloner(other.ptr);
        cloner = other.cloner;
    }
    void swap( clone_ptr& other ) noexcept
    {
        using std::swap;
        swap( ptr,    other.ptr    );
        swap( cloner, other.cloner );
    }

    clone_ptr& operator=( const clone_ptr& other )
    {
        clear();
        ptr = other.cloner(other.ptr);
        cloner = other.cloner;
        return *this;
    }
    clone_ptr& operator=( clone_ptr&& other )
    {
        clear();
        swap(other);
        return *this;
    }

    T* operator->() { return ptr; }
    const T* operator->() const { return ptr; }
    T& operator*() { return *ptr; }
    const T& operator*() const { return *ptr; }

    operator bool() const { return ptr; }

    bool operator"; return os ; }

    template
    void make( Ts&& ...ts )
    {
        clear();
        ptr = new T2( std::forward(ts)... );
        cloner = [](T* p) -> T* { return new T2( * (T2*) p ); };
    }

    void clear() { delete ptr; ptr=nullptr; cloner=nullptr; }

    ~clone_ptr() { clear(); }

private:
    T* ptr;
    std::function cloner;
};

template
clone_ptr make_cloned( Ts&& ...ts )
{
    clone_ptr p;
    p.template make( std::forward(ts)... );
    return p;
}

template
std::ostream& operator& p) { return p.output(os); }


It is primarily intended to preserve polymorphism, esp. when stored in a container. It "forwards" operator< and operator== so containers can be sorted etc. based on the contained object.

Have I missed/forgotten anything?

Solution

Prefer to use Copy and Swap Idiom

clone_ptr& operator=( const clone_ptr& other )
{
    clear();
    ptr = other.cloner(other.ptr);
    cloner = other.cloner;
    return *this;
}


Or

clone_ptr& operator=(clone_ptr copy)
{
    copy.swap(*this);
    return *this;
}


No need to clear on move assignment

clone_ptr& operator=( clone_ptr&& other )
{
    // clear();   No need to do that.
                  The destructor of `other` will do that at some point.
    swap(other);
    return *this;
}


Easier to write as:

clone_ptr& operator=(clone_ptr copy)
{
    copy.swap(*this);
    return *this;
}


Personally I don't see the point in havin output() and operator<<

I would just combine them into operator<< and make it a friend (also declare it in the class).

Code Snippets

clone_ptr& operator=( const clone_ptr& other )
{
    clear();
    ptr = other.cloner(other.ptr);
    cloner = other.cloner;
    return *this;
}
clone_ptr& operator=(clone_ptr copy)
{
    copy.swap(*this);
    return *this;
}
clone_ptr& operator=( clone_ptr&& other )
{
    // clear();   No need to do that.
                  The destructor of `other` will do that at some point.
    swap(other);
    return *this;
}
clone_ptr& operator=(clone_ptr copy)
{
    copy.swap(*this);
    return *this;
}

Context

StackExchange Code Review Q#92593, answer score: 3

Revisions (0)

No revisions yet.