How to provide custom deleter in my class unique_ptr? - c++

I've implemeted my unique_ptr:
template<class T, typename D = default_deleter<T> >
class unique_ptr
{
private:
T* _ptr;
D deleter;
public:
//Default constructor
explicit unique_ptr(void): _ptr(nullptr) { }
//Constructor with the provided pointer to manage
unique_ptr(T* p) throw() : _ptr(p), deleter(default_deleter<T>())
{ }
unique_ptr(T* p, D d) throw() : _ptr(p), deleter(d) { }
~unique_ptr(void) throw() // never throws
{
delete _ptr;
_ptr = nullptr;
}
Here it is a default_deleter
template<typename T>
struct default_deleter
{
default_deleter() { }
template<typename _Up>
default_deleter(const default_deleter<_Up>&) { }
void operator()(T* p) const
{
delete p;
}
};
but when I am trying to use custom deleter:
struct MyCustomDeleter {
void operator()(SomeResource* p) {
p->releaseResources();
delete p;
}
};
int main() {
unique_ptr<SomeResource, MyCustomDeleter> ptr1(new SomeResource(1));
I get
no matching function for call to 'MyCustomDeleter::MyCustomDeleter(default_deleter)'

You always initialize your unique_ptr with the default deleter, but there are inconsistencies in your code.
template<class T, typename D = default_deleter<T> >
class unique_ptr
{
private:
T* _ptr;
D deleter; // you do not need this, since the type is known at c-t
public:
//Default constructor
explicit unique_ptr(void): _ptr(nullptr) { } // but no initialization of D
//Constructor with the provided pointer to manage
unique_ptr(T* p) throw() : _ptr(p), deleter(default_deleter<T>()) // wrong D !!
{ }
unique_ptr(T* p, D d) throw() : _ptr(p), deleter(d) { } // weird
};
You know the deleter at compile-time.
template<class T, typename D = default_deleter<T> >
class unique_ptr
{
private:
T* ptr_{nullptr};
public:
explicit unique_ptr(T* ptr) noexcept : ptr_(ptr) {}
unique_ptr() noexcept = default;
unique_ptr(const unique_ptr&) = delete;
unique_ptr(unique_ptr&& x) noexcept : ptr_(x.release()) {}
~unique_ptr() noexcept(noexcept(D(T*{}))) { reset(); }
void reset() noexcept(noexcept(D(T*{})))
{ if (ptr_) { D(ptr_); } ptr_ = nullptr; }
T* release() noexcept { auto p = ptr_; ptr_ = nullptr; return p; }
unique_ptr& operator= (const unique_ptr&) = delete;
unique_ptr& operator= (unique_ptr&& x) noexcept(noexcept(D(T*{})))
{ reset(); ptr_ = x.release(); return *this; };
// ... operators op*, ->, etc...
};
If you want to specify a deleter at run-time, it should not be a template parameter.

Related

Why can't I have std::optional<T> where T is abstract?

This does not work:
struct Type {
virtual bool func(const std::string& val) const noexcept = 0;
}
// in main
optional<Type> = some_function_returning_optional_type();
and fails with a error message:
error: cannot declare field 'std::experimental::fundamentals_v1::_Optional_base<Type, false>::<anonymous union>::_M_payload' to be of abstract type 'Type'
Changing the Type to have a non-pure function works, but is not appropriate in this case, because there cannot be an instance of Type in my code, only classes which inherit from it should be able to exist.
std::optional<T> stores its value in-place - it therefore needs to know the size of T to work correctly, and T must be a concrete type that can be instantiated. You can think of std::optional<T> as:
template <typename T>
struct optional
{
std::aligned_storage_t<sizeof(T), alignof(T)> _data;
bool _set;
};
An abstract type represents an interface - polymorphism and some sort of indirection are required to work with abstract types. std::optional doesn't have any indirection by design.
Your proposal of optional will of course work but it would offend me to have to write
x.value()->do_something();
and I'd be concerned that users might do something daft:
x.value().reset(); // now what?
We can achieve polymorphism with a non-polymorphic interface by using a wrapper.
Here's one way:
#include <optional>
#include <iostream>
// the Foo interface/base class
struct Foo
{
virtual ~Foo() = default;
virtual Foo* clone() const { return new Foo(*this); }
virtual void do_something() {
std::cout << "something Fooey\n";
}
};
// a service for managing Foo and classes derived from Foo
struct FooService
{
template<class Arg>
Foo* clone(Arg&& arg)
{
using d_type = std::decay_t<Arg>;
return new d_type(std::forward<Arg>(arg));
}
template<class Arg>
Foo* clone(Foo* arg)
{
return arg->clone();
}
Foo* release(Foo*& other) noexcept
{
auto tmp = other;
other = nullptr;
return tmp;
}
};
// implement the Foo interface in terms of a pimpl
template<class Holder>
struct BasicFoo
{
decltype(auto) do_something() {
return get().do_something();
}
private:
Foo& get() noexcept { return static_cast<Holder*>(this)->get_impl(); }
Foo const& get() const noexcept { return static_cast<Holder const*>(this)->get_impl(); }
};
// a type for holding anything derived from a Foo
// can be initialised by anything Foo-like and handles copy/move correctly
struct FooHolder : BasicFoo<FooHolder>
{
template
<
class Arg,
std::enable_if_t
<
std::is_base_of_v<Foo, std::decay_t<Arg>>
>* = nullptr
>
FooHolder(Arg&& arg)
: service_()
, ptr_(service_.clone(std::forward<Arg>(arg)))
{}
FooHolder(FooHolder const& other)
: service_()
, ptr_(other.ptr_->clone())
{
}
FooHolder(FooHolder && other) noexcept
: service_()
, ptr_(service_.release(other.ptr_))
{
}
FooHolder& operator=(FooHolder const& other)
{
auto tmp = other;
std::swap(ptr_, tmp.ptr_);
return *this;
}
FooHolder& operator=(FooHolder && other) noexcept
{
auto tmp = std::move(other);
std::swap(ptr_, tmp.ptr_);
return *this;
}
~FooHolder()
{
delete ptr_;
}
Foo& get_impl() noexcept { return *ptr_; }
Foo const& get_impl() const noexcept { return *ptr_; }
FooService service_;
Foo* ptr_;
};
// now we can supply as many overrides of Foo as we like
struct Bar : Foo
{
virtual Foo* clone() const { return FooService().clone(*this); }
virtual void do_something() {
std::cout << "something Barey\n";
}
};
int main()
{
std::optional<FooHolder> opt;
// note that we're initialising cleanly
opt = Bar {};
// and we don't expose the pointer so the user can't
// destroy the pimpl accidentally
opt.value().do_something();
}

invalid initialization of non-const reference of type from an rvalue of type

I am writing some code based on issue 28 smart pointer of more effective c++ as follows. However, it cannot compile:
main.cpp: In instantiation of 'SmartPointer<T>::operator SmartPointer<U>() [with U = MusicProduct; T = Cassette]':
main.cpp:99:17: required from here
main.cpp:48:39: error: invalid initialization of non-const reference of type 'SmartPointer<MusicProduct>&' from an rvalue of type 'SmartPointer<MusicProduct>'
return SmartPointer<U> (ptr_);
^
main.cpp:16:9: note: initializing argument 1 of 'SmartPointer<T>::SmartPointer(SmartPointer<T>&) [with T = MusicProduct]'
SmartPointer(SmartPointer<T>& other)
^
Either of these two changes works:
in the implementation of operator SmartPointer (), create an object and return:
SmartPointer a(ptr_);
return a;
Or, make the parameter of the copy constructor as const
SmartPointer(const SmartPointer& other)
and comment the line
other.ptr_ = nullptr;
Is there any reason why either of the solutions works? Thanks.
#include <iostream>
template <typename T>
class SmartPointer
{
public:
SmartPointer(T* ptr) : ptr_(ptr) {}
~SmartPointer()
{
if (ptr_)
{
delete ptr_;
}
}
SmartPointer(SmartPointer<T>& other)
{
ptr_ = other.ptr_;
other.ptr_ = nullptr;
}
SmartPointer<T>& operator = (SmartPointer<T>& other)
{
if (this == &other)
{
return *this;
}
if (ptr_)
{
delete ptr_;
}
ptr_ = other.ptr_;
other.ptr_ = nullptr;
return *this;
}
template <typename U>
operator SmartPointer<U> ()
{
// it works
//SmartPointer<U> a(ptr_);
//return a;
// error
return SmartPointer<U> (ptr_);
}
T& operator * () const
{
return *ptr_;
}
T* operator -> () const
{
return ptr_;
}
private:
T* ptr_ = nullptr;
};
class MusicProduct
{
public:
MusicProduct(const std::string& name) : name_(name) {}
virtual ~MusicProduct() {}
virtual void Play() const = 0;
virtual void ShowName() const
{
std::cout << name_ << std::endl;
}
private:
std::string name_;
};
class Cassette : public MusicProduct
{
public:
Cassette(const std::string& name) : MusicProduct(name) {}
void Play () const
{
std::cout << "play cassette" << std::endl;
}
};
void CallPlay(const SmartPointer<MusicProduct>& sp)
{
sp->Play();
}
int main()
{
SmartPointer<Cassette> a(new Cassette("Zhang"));
a->ShowName();
CallPlay(a);
return 0;
}
That's because your copy ctor has a non-const reference parameter and therefore cannot accept a temporary. Thus
return SmartPointer<X>(y);
won't work. The argument to the return keyword is a temporary, and it needs to be copied, so here the design breaks down.
Since you are using C++11, you can fix this by introducing a move constructor (and move assignment).
You can also make the argument const and designate the ptr_ member as mutable. This will allow you to copy from temporaries and const smart pointers, but for the price of actually mutating them.

Calling function with different argument C++

This question is just for improvement purpose. There is a function below:
void Func_A(u8* arg) {
bool local_arg=false;
if(!arg) {
//allocate memory for arg
local_arg=true;
}
//process arg
I am calling this function from multiple places with NULL and non NULL argument.
I just want to ask whther there is a better way of handling such this without local_arg or not.
You can sometimes use...
u8* p = arg ? arg : new u8(...);
...do things with *p...
if (!arg) delete p;
A little fancier, you can write a smart pointer with runtime-configurable ownership:
template <typename T>
class Uncertain_Ownership_Ptr
{
public:
enum Ownership { Own_It, Dont_Own_It };
Uncertain_Ownership_Ptr(T* p, Ownership own) : p_(p), own_(own) { }
Uncertain_Ownership_Ptr(const Uncertain_Ownership_Ptr&) = delete;
void operator=(const Uncertain_Ownership_Ptr&) = delete;
~Uncertain_Ownership_Ptr() { if (own_ == Own_It) delete p_; }
T& operator*() { return *p_; }
const T& operator*() const { return *p_; }
T* operator->() { return p_; }
const T* operator->() const { return p_; }
private:
T* p_;
Ownership own_;
};
...then...
void Func_A(u8* arg)
{
Uncertain_Ownership_Ptr p(arg ? arg : new u8(...),
arg ? Uncertain_Ownership_Ptr::Dont_Own_It : Uncertain_Ownership_Ptr::Own_It);
// use *p ...
}

How to implement deep copy feature in some smart pointer?

unique_ptr is quite useful. However, it is not copyable. If virutal clone (deep copy) methods are provided for its pointed class, I think it will become more useful. Is it necessary or any better way to implement it? Any similar smart pointer exist in some library? Here is a version
template<class T>
class deep_ptr: private unique_ptr<T>
{
public:
using unique_ptr<T>::operator *;
using unique_ptr<T>::operator ->;
using unique_ptr<T>::operator bool;
using unique_ptr<T>::release;
using unique_ptr<T>::reset;
using unique_ptr<T>::get;
// add (DEFAULT_CONSTRUCTOR)(MOVE_CONSTRUCTOR)(MOVE_ASSIGNMENT_METHOD) ...
explicit deep_ptr(T* p) : unique_ptr(p) {}
deep_ptr(deep_ptr const& r) : unique_ptr(r->clone()) {}
deep_ptr& operator=(deep_ptrconst& r)
{ if (this != &r) reset(r->clone()); return *this; }
};
Juse feel it is very useful but never see similar things. ???
Unless I am misunderstanding what you are looking for, if a class has a clone method, that should be sufficient to get what you are looking for.
Sample code:
#include <iostream>
#include <memory>
struct A
{
virtual ~A() {}
virtual A* clone() = 0;
};
struct B : A
{
B(int in = 0) : x(in) {}
B(B const& copy) : x(copy.x) {}
virtual ~B() {std::cout << "In B::~B()\n";}
virtual A* clone() { return new B(*this); }
int x;
};
int main()
{
std::unique_ptr<A> p1(new B(10));
std::unique_ptr<A> p2(p1->clone());
return 0;
}
Output from running the above program:
In B::~B()
In B::~B()
Without a clone method (just a copy-constructor) the following should work:
template <typename T>
class deep_ptr
{
public:
deep_ptr() : i_() {}
deep_ptr(std::nullptr_t) : i_(nullptr) {}
template <typename U>
deep_ptr(U* u) : i_(u ? new inner_impl<U>(*u) : nullptr) {}
~deep_ptr() { delete i_; }
deep_ptr(const deep_ptr& p) : i_(p.i_ ? p.i_->copy() : nullptr) {}
deep_ptr& operator=(const deep_ptr& p)
{
if (!p.i_) { i_ = nullptr; }
else { i_ = p.i_->copy(); }
}
deep_ptr(deep_ptr&& p) : i_(p.i_) { p.i_ = nullptr; }
deep_ptr& operator=(deep_ptr&& p)
{
i_ = p.i_;
p.i_ = nullptr;
}
const T* operator->() const { return get(); }
const T* get() const
{
if (i_) { return *i_; }
return nullptr;
}
const T& operator*() const { return *static_cast<T*>(*i_); }
T* operator->() { return get(); }
T* get()
{
if (i_) { return *i_; }
return nullptr;
}
T& operator*(){ return *static_cast<T*>(*i_); }
private:
struct inner
{
virtual inner* copy() const = 0;
virtual operator const T*() const = 0;
virtual operator T*() = 0;
virtual ~inner() {}
};
inner* i_;
template <typename U>
struct inner_impl : inner
{
inner_impl(const U& u) : u_(u) {}
inner_impl* copy() const override { return new inner_impl(u_); }
operator const T*() const override { return &u_; }
operator T*() override { return &u_; }
U u_;
};
};

C++ void* any type implementation returns weird result

I am trying to make a basic any type implementation in C++ (object), yet it always prints CCCCCCCC if I want to get the value from any type, and it is confusing me why (although I do know void*s are dangerous):
#include <typeinfo>
struct object
{
private:
template < typename T > struct _base
{
typedef T _ptr_type;
_ptr_type* _ptr_val()
{
return _ptr;
}
_base(_ptr_type value) : _ptr(&value){}
_base() : _ptr(nullptr){}
_ptr_type* _ptr;
};
struct _holder : _base<void*>
{
template < typename Ty > void cast(const _base<Ty>* p_base)
{
_ptr->~_ptr_type();
_ptr_type _n_type = (_ptr_type)p_base->_ptr, *_n_ptr = &_n_type;
std::swap<_ptr_type*>(_ptr, _n_ptr);
}
_holder(){}
};
public:
_holder* _h_ptr;
object() : _h_ptr(new _holder){}
template < typename T > object(const T& value) : _h_ptr(new _holder)
{
_base<T> _t_base(value);
_h_ptr->cast(&_t_base);
}
template < typename T > void operator=(const T& value)
{
_base<T> _t_base(value);
_h_ptr->cast(&_t_base);
}
const void* operator()() const
{
return *_h_ptr->_ptr_val();
}
};
#include <iostream>
int main()
{
object MyObject = 'c';
std::cout << MyObject();
getchar();
}
Perhaps my implementation of the object class will help you. It is similar to boost::any, but has a few more features (operator== and operator!=)
class object
{
private:
class dummy
{
public:
dummy()
{
}
virtual ~dummy()
{
}
virtual const std::type_info &type() const = 0;
virtual dummy *duplicate() const = 0;
virtual bool eq(object) = 0;
};
template < typename _Ty > class data : public dummy
{
public:
data()
{
}
data(const _Ty &_Value)
: __data(_Value)
{
}
~data()
{
}
const std::type_info &type() const
{
return typeid(_Ty);
}
data *duplicate() const
{
return new data<_Ty>(__data);
}
bool eq(object _Obj)
{
return _Obj.cast<_Ty>() == __data;
}
_Ty __data;
};
dummy *d;
public:
object()
{
}
template < typename _Ty > object(const _Ty &_Value)
: d(new data<_Ty>(_Value))
{
}
object(const object &_Obj)
: d(_Obj.d->duplicate())
{
}
~object()
{
if (!empty())
{
delete d;
}
}
const std::type_info &type() const
{
return (empty() ? typeid(void) : d->type());
}
object &operator=(object &_Rhs)
{
if (&_Rhs != this)
{
d = _Rhs.d->duplicate();
}
return *this;
}
object &swap(object &_Rhs)
{
std::swap(*this, _Rhs);
return *this;
}
template < typename _Ty > object &operator=(const _Ty &_Value)
{
d = new data<_Ty>(_Value);
return *this;
}
template < typename _Ty > _Ty cast() const
{
if (type() == typeid(_Ty))
{
return static_cast<data<_Ty> *>(d)->__data;
}
throw std::exception("Invalid cast type");
}
bool operator==(const object &_Rhs) const
{
return (type() == _Rhs.d->type() ? d->eq(_Rhs) : false);
}
template < typename _Ty > bool operator==(_Ty _Value) const
{
return (type() == typeid(_Ty) ? cast<_Ty>() == _Value : false);
}
bool operator!=(const object &_Rhs) const
{
return !(*this == _Rhs);
}
template < typename _Ty > bool operator!=(_Ty _Value) const
{
return !(*this == _Value);
}
bool empty() const
{
return !d;
}
};
I am afraid just like boost::any, there is no getter function, but a cast function. It can be used like this
int main()
{
object o = 5;
object o = (std::string)"Hello\n"; // doesn't like arrays, must be wrapped in a class
std::cout << o.cast<std::string>().c_str();
}
I'm sorry, but your implementation makes absolutely no sense whatsoever. It seems to be based on a completely flawed understanding of memory and the C++ object model, as well as templates. I think in your example program execution, every line of cast invokes undefined behavior, to the point where it's impossible to say what actually happens.
Throw it away and start again from scratch.
template < typename T > struct _base
{
typedef T _ptr_type;
_base(_ptr_type value) : _ptr(&value){}
_ptr_type* _ptr;
};
Well, the constructor recieves a _ptr_type by value, which means a temporary copy on the stack. _ptr(&value) makes the internal pointer point at this temporary. Then the constructor returns, and the temporary is destroyed, making this entire class broken. I'm not sure what the point of this class is yet, so I cannot make suggestions as to how to fix it.
struct _holder : _base<void*>
{
template < typename Ty > void cast(const _base<Ty>* p_base)
{
_ptr->~_ptr_type();
_ptr_type _n_type = (_ptr_type)p_base->_ptr, *_n_ptr = &_n_type;
std::swap<_ptr_type*>(_ptr, _n_ptr);
}
};
I don't know what this is for either, but the first step of your cast is to destroy the data. That's... probably a bad idea. Then you point _n_type at the data of p_base, and then make this->_ptr point at the temporary _n_type pointer which is on the stack, which means that when the function ends, this->_ptr points at invalid data again.
I have no idea how you thought this was supposed to work, so here's a rundown of the normal interface for this sort of thing:
struct object
{
private:
//base is a non-template, pure virtual interface
//used to store and access all internal data
//without knowing the actual type
struct _interface //not a template
{
virtual ~_interface () =0 {};
//clone allows us to copy without knowing the type
virtual std::unique_ptr<_interface> clone() const = 0 {}
};
//this actually stores the data
//it may be given other members, but using these
//members requires `object` to know the type
template< typename T>
struct data: _interface
{
//data() : _data() {} //default constructor - not used
//data(const data& rhs) : _data(rhs._data) {} //copy constructor - not used
//data(data&& rhs) : _data(std::move(rhs._data)) {} //move constructor - not used
data(const T& rhs) : _data(rhs) {} //value by copy
data(T&& rhs) : _data(std::move(rhs)) {} //value by move
template< typename... Us>
data(Us&&...vs) : _data(std::forward<Us>(vs)...) {} //emplace constructor
std::unique_ptr<_interface> clone() const //virtual cloning mechanism
{return std::unique_ptr<data>(new T(_data));}
T _data;
};
std::unique_ptr<_interface> _ptr;
public:
object() //default constructor
: _ptr() {}
object(const object&& rhs) //copy constructor
: _ptr(rhs ? rhs._ptr->clone() : {}) {}
object(object&& rhs) //move constructor
: _ptr(std::move(rhs._ptr)) {}
template < typename U> object(const U& _Value) //value by copy
: _ptr(new data<U>(_Value)) {}
template < typename U> object(U&& _Value) //value by move
: _ptr(new data<U>(std::move(_Value)) {}
object& operator=(const object& rhs) //copy assignment
{_ptr = rhs ? rhs._ptr->clone() : {}; return *this;}
object& operator=(object&& rhs) //move assignment
{_ptr = std::move(rhs._ptr); return *this;}
//*_ptr gives you a _interface&
//dynamic_cast<data<T>&> gives you a _data<T>& or throws a std::bad_cast
//._data gives the actual value
template< typename T> T& get()
{return dynamic_cast<data<T>&>(*_ptr)._data;}
template< typename T> const T& get() const
{return dynamic_cast<const data<T>&>(*_ptr)._data;}
explicit operator bool() const {return _ptr;} //object o; if (o) then ....
};
This only handles bare basics. Everything else is left up to you.