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_;
};
};
Related
Got this code (should be all that is relevant):
//movable_ptr.hpp
//Michal Cermak
#ifndef MOVABLE_H
#define MOVABLE_H
template<typename T> class movable_ptr;
template<typename T> class enable_movable_ptr {
public:
//default constructor
enable_movable_ptr() {};
enable_movable_ptr(T* p) : ptr_(p) {};
//operators...
T& operator*() const { return *ptr_; };
T* operator->() const { return ptr_; };
bool operator==(const enable_movable_ptr<T>& p) const { return p.ptr_ == ptr_; };
T* get() {return ptr_; };
private:
T* ptr_ = nullptr;
};
template<typename T> class movable_ptr {
public:
//parameterless constructor
movable_ptr() {};
//constructor from T*
movable_ptr(T* p) : ptr_(p) { add_to_tracked(this); };
//operators ...
enable_movable_ptr<T>& operator*() const { return *ptr_; };
enable_movable_ptr<T>* operator->() const { return ptr_; };
bool operator==(const movable_ptr<T>& p) const { return p.ptr_ == ptr_; };
//access to variables
enable_movable_ptr<T>* get() {return ptr_; };
void set(enable_movable_ptr<T>* p) { ptr_ = p; };
private:
enable_movable_ptr<T>* ptr_ = nullptr;
};
template<typename T> movable_ptr<T> get_movable(enable_movable_ptr<T>& p){
return new movable_ptr<T>(p);
};
#endif
My problem is that when I run the following code (or other similar ones for that matter), the movable_ptr<T> doesn't get de-referenced all the way to A, but gets stuck on enable_movable_ptr<A>, which causes comparisons and other stuff to throw errors, because "'val' is not a member of enable_movable_ptr<A>". It is a member of A though, so if I de-reference correctly, it should then work.
#include <iostream>
#include <memory>
#include <string>
#include "movable_ptr.hpp"
using namespace std;
class A : public enable_movable_ptr<A>
{
public:
int val;
A(int val) : val(val) {}
};
void test_ptr_dereference() {
A x(42);
auto px = get_movable(x);
TEST_ASSERT(&*px == &x);
TEST_ASSERT(&px->val == &x.val);
}
int main(int argc, char* argv[]) {
test_ptr_dereference();
}
I am guessing I did something wrong in the overloaded operators, but otherwise have no clue. Any ideas on how to fix it?
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();
}
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.
I'm attempting to re-create the any that is found in Boost::any and I have built the three classes, however, whenever I come to reinterpret_cast for the value that is given, the output is completely different and just throws out garbage. Here is my code below:
namespace Types {
class PlaceMaker {
public:
PlaceMaker() { };
virtual ~PlaceMaker()
{
}
virtual PlaceMaker * clone()
{
return 0;
}
virtual const std::type_info & type() const = 0;
protected:
};
template<typename T>
class holder : public PlaceMaker {
public:
holder(const T & value)
: held(value)
{
}
virtual const std::type_info & type() const
{
return typeid(T);
}
virtual PlaceMaker * clone() const
{
return new holder(held);
}
T retrunHeld() const {
return held;
}
public:
T held;
//holder &operator=(const holder &) const = 0;
holder & operator=(const holder &) { }
};
class Any : PlaceMaker {
public:
Any() : maker(0) { };
template<typename ValueType>
Any(const ValueType & value)
: maker(new holder<ValueType>(value))
{
}
Any(const Any & other)
: maker(other.maker ? other.maker->clone() : 0)
{
}
Any& swap(Any &rhs) {
std::swap(maker, rhs.maker);
return *this;
}
template<typename ValueType>
Any & operator=(const ValueType & rhs)
{
Any(rhs).swap(*this);
return *this;
}
Any & operator=(Any rhs)
{
rhs.swap(*this);
return *this;
}
bool empty() const
{
return !maker;
}
const std::type_info & type() const
{
return maker ? maker->type() : typeid(void);
}
template<typename T>
T& cast() {
T* r = reinterpret_cast<T*>(maker);
return *r;
}
public:
PlaceMaker * maker;
};
In main I have the following:
int main() {
Types::Any a = 10;
std::cout << a.cast<int>();
}
// output: 96458224
Could anyone tell me as to where I'm going wrong?
Thanks
You're casting a Holder* to a T*. Given that Holder has virtual functions in it, that means you're gonna be looking at the vtable, not the T itself.
My abstract Reference counter class:
template<class T>
class ReferenceCounter
{
public:
ReferenceCounter();
~ReferenceCounter();
void addRef();
void release();
uint32 getCountReferences() const;
protected:
int32* pCountReferences;
virtual void destroyObject() = 0;
virtual void shallowCopy(const T& rhs) = 0;
};
template<class T>
inline ReferenceCounter<T>::ReferenceCounter()
{
pCountReferences = new int32;
*pCountReferences = 1;
}
template<class T>
inline ReferenceCounter<T>::~ReferenceCounter()
{
if(pCountReferences != NULL && *pCountReferences == 0)
{
delete pCountReferences;
pCountReferences = NULL;
}
}
template<class T>
inline void ReferenceCounter<T>::addRef()
{
debug_assert((*pCountReferences) >= 0, "Incorrect value of count references");
++(*pCountReferences);
}
template<class T>
inline void ReferenceCounter<T>::release()
{
debug_assert((*pCountReferences) > 0, "Incorrect value of count references");
(*pCountReferences)--;
if(pCountReferences != NULL && *pCountReferences == 0)
{
destroyObject();
}
}
template<class T>
inline uint32 ReferenceCounter<T>::getCountReferences() const
{
return *pCountReferences;
}
This is my smart pointer :
template<class T>
class SmartPtr
{
public:
SmartPtr();
SmartPtr(T* pInst);
SmartPtr(const SmartPtr<T>& rhs);
~SmartPtr();
void operator = (const SmartPtr<T>& rhs);
T* operator -> () const;
T* getData() const;
bool isNULL() const;
private:
T* pInst;
};
template<class T>
SmartPtr<T>::SmartPtr() : pInst(NULL) {}
template<class T>
SmartPtr<T>::SmartPtr(T* pInst) : pInst(pInst) {}
template<class T>
SmartPtr<T>::~SmartPtr()
{
if(pInst != NULL)
{
pInst->release();
}
}
template<class T>
SmartPtr<T>::SmartPtr(const SmartPtr<T>& rhs)
{
this->pInst = rhs.pInst;
if(pInst != NULL)
{
pInst->addRef();
}
}
template<class T>
void SmartPtr<T>::operator= (const SmartPtr<T>& rhs)
{
this->pInst = rhs.pInst;
if(pInst != NULL)
{
pInst->addRef();
}
}
template<class T>
T* SmartPtr<T>::operator->() const
{
return pInst;
}
template<class T>
T* SmartPtr<T>::getData() const
{
return pInst;
}
template<class T>
bool SmartPtr<T>::isNULL() const
{
return pInst == NULL;
}
There are test of code :
#include <iostream>
#include "ReferenceCounter.h"
#include "SmartPtr.h"
using namespace std;
class B;
class A : public ReferenceCounter<A>
{
public:
A();
A(const A& rhs);
~A();
SmartPtr<B> getB();
void operator = (const A& rhs);
private:
void destroyObject();
void shallowCopy(const A& rhs);
};
class B : public ReferenceCounter<B>
{
private:
void destroyObject() {} ;
void shallowCopy(const B& rhs) {};
};
A::A()
{
cout << "Create object" << endl;
}
A::A(const A& rhs)
{
shallowCopy(rhs);
addRef();
cout << "copy constructor " << endl;
}
A::~A()
{
release();
}
void A::destroyObject()
{
cout << "destroy" << endl;
}
void A::shallowCopy(const A& rhs)
{
this->pCountReferences = rhs.pCountReferences;
}
void A::operator = (const A& rhs)
{
shallowCopy(rhs);
addRef();
cout << "operator = " << endl;
}
SmartPtr<B> A::getB()
{
return SmartPtr<B>(new B());
}
SmartPtr<A> getA()
{
SmartPtr<A> a(new A());
return a;
}
int main()
{
getA();
return 0;
}
This code is worked but below not called copy constructor of smart pointer when i debug this code . What problems happens below ??
int main()
{
A a;
a.getB();
}
See here for Return value optimization.
The compiler is allowed, to eliminate the copy of a temporary object being returned.
With C++11, there's also the possibility of moving an object. See What are move semantics? for an explanation.
Update:
This is not a problem at all, just a compiler optimization.
As long as there's nothing special going on in your constructor and destructor, there's no need to prevent this optimization. You should allow this instead, because it makes your program run faster by skipping one constructor and one destructor call.