Skip to content

Instantly share code, notes, and snippets.

@SeanCline
Last active April 27, 2016 17:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SeanCline/416e6d42e0a4c9bf8fbf15126fdd6847 to your computer and use it in GitHub Desktop.
Save SeanCline/416e6d42e0a4c9bf8fbf15126fdd6847 to your computer and use it in GitHub Desktop.
A quick (mostly untested) go at a `clone_ptr` implementation that keeps from slicing polymorphic objects by type erasing their copy constructor and storing them in the clone_ptr.
#pragma once
#include <memory>
#include <utility>
#include <type_traits>
#include <functional> // TODO: Stop using functional.
template <class T>
struct default_clone {
T* operator()(const T* ptr) const
{
return new T(*ptr);
}
};
template<class T>
class clone_ptr {
template <typename T2> friend class clone_ptr;
public: // Typedefs.
using pointer = T*;
using element_type = T;
using deleter_type = std::function<void(pointer)>; // TODO: Stop using functional.
using cloner_type = std::function<pointer(pointer)>; // TODO: Stop using functional.
public: // Rule of whatever.
template <class Cloner = default_clone<element_type>, class Deleter = std::default_delete<element_type>>
explicit clone_ptr(T* ptr = nullptr, Cloner cloner = default_clone<element_type>(), Deleter deleter = std::default_delete<element_type>())
: ptr_(ptr),
deleter_(deleter),
cloner_(cloner)
{
}
clone_ptr(const clone_ptr& other)
: ptr_(other.clone()),
deleter_(other.deleter_),
cloner_(other.cloner_)
{
}
clone_ptr(clone_ptr&& other)
: ptr_(std::move(other.ptr_)),
deleter_(std::move(other.deleter_)),
cloner_(std::move(other.cloner_))
{
other.ptr_ = nullptr;
}
template <typename T2>
clone_ptr(const clone_ptr<T2>& other)
: ptr_(other.clone()),
deleter_([deleter = other.deleter_](pointer p) { return deleter(static_cast<T2*>(p)); }),
cloner_([cloner = other.cloner_](pointer p) { return cloner(static_cast<T2*>(p)); })
{
}
template <typename T2>
clone_ptr(clone_ptr<T2>&& other)
: ptr_(std::move(other.ptr_)),
deleter_([deleter = std::move(other.deleter_)](pointer p) { return deleter(static_cast<T2*>(p)); }),
cloner_([cloner = std::move(other.cloner_)](pointer p) { return cloner(static_cast<T2*>(p)); })
{
other.ptr_ = nullptr;
}
clone_ptr& operator=(const clone_ptr& other)
{
reset(other.clone());
deleter_ = other.deleter_;
cloner_ = other.cloner_;
return *this;
}
clone_ptr& operator=(clone_ptr&& other)
{
reset(std::move(other.ptr_));
deleter_ = std::move(other.deleter_);
cloner_ = std::move(other.cloner_);
other.ptr_ = nullptr;
return *this;
}
template <typename T2>
clone_ptr& operator=(clone_ptr<T2>&& other) {
reset(std::move(other.ptr_));
deleter_ = [deleter = std::move(other.deleter_)](pointer p) { return deleter(static_cast<T2*>(p)); };
cloner_ = [cloner = std::move(other.cloner_)](pointer p) { return cloner(static_cast<T2*>(p)); };
other.ptr_ = nullptr;
return *this;
}
void swap(clone_ptr& other)
{
swap(ptr_, other.ptr_);
swap(deleter_, other.deleter_);
swap(cloner_, other.cloner_);
}
~clone_ptr()
{
if (ptr_) reset();
}
public: // Indirection/access.
element_type& operator*()
{
return *ptr_;
}
const element_type& operator*() const
{
return *ptr_;
}
pointer operator->()
{
return ptr_;
}
const pointer operator->() const
{
return ptr_;
}
pointer get()
{
return ptr_;
}
const pointer get() const
{
return ptr_;
}
public: // Comparison.
explicit operator bool() const
{
return ptr_ != nullptr;
}
bool operator==(const clone_ptr& other) const
{
return ptr_ == other.ptr_;
}
bool operator!=(const clone_ptr& other) const
{
return ptr_ != other.ptr_;
}
bool operator<(const clone_ptr& other) const
{
return ptr_ < other.ptr_;
}
bool operator>(const clone_ptr& other) const
{
return ptr_ > other.ptr_;
}
bool operator>=(const clone_ptr& other) const
{
return ptr_ >= other.ptr_;
}
bool operator<=(const clone_ptr& other) const
{
return ptr_ <= other.ptr_;
}
public: // Methods.
void reset(pointer ptr = pointer())
{
deleter_(ptr_);
ptr_ = ptr;
}
void release()
{
auto old = ptr_;
ptr_ = nullptr;
return old;
}
private:
pointer clone() const
{
return cloner_(ptr_);
}
private:
pointer ptr_;
deleter_type deleter_;
cloner_type cloner_;
};
template<class T, class... Args>
clone_ptr<T> make_clone_ptr(Args&&... args)
{
return clone_ptr<T>(new T(std::forward<Args>(args)...));
}
#include "clone_ptr.h"
#include <iostream>
using namespace std;
struct SqualkB {
virtual void squalk() const
{
cout << "SqualkB!\n";
}
};
struct SqualkD : SqualkB {
SqualkD()
{
cout << "SqualkD : default ctor\n";
}
SqualkD(const SqualkD&)
{
cout << "SqualkD : copy ctor\n";
}
~SqualkD()
{
cout << "SqualkD : dtor\n";
}
void squalk() const override
{
cout << "SqualkD!\n";
}
};
int main()
{
auto squalkD = make_clone_ptr<SqualkD>();
auto squalkD2 = squalkD;
clone_ptr<SqualkB> squalkB = squalkD;
squalkD->squalk();
squalkD2->squalk();
squalkB->squalk();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment