I recently wanted to use a list of different derived classes, as one does quite often, but also wanted it to be copyable. Because of this I couldn't use something like std::unique_ptr
or std::shared_ptr
since when copying, I want not only the pointer but also the pointed to object in memory to be duplicated.After some research I found out about the clone pattern, the use of something called CRTP, and some other (though rather unconvenient) ways. Although a clone method in every class makes sense, it seems very redundant because it's the same code every time. Regarding CRTP I thought a new class is a bit much as you know the type of the currently stored derived through the set method template (see code) and would just need to save it for creating a new object of it later when copying.
I now implemented my own version which solves my copy problem but I am wondering why I haven't found something like this proposed elsewhere? Are there any drawbacks to using this, or is there anything I've missed with this?I don't know if there even is a way of storing which datatype something is (typedef
and decltype
are not settable variable-alikes), so I used a std::function
whose return type is dynamically overwritten.
Here's the implementation I have:(Sure, there are still some things to add, like a direct assignment operator overload, and stuff, but for now it's okay like this)
template <typename BaseType>class PolyPtr {private: BaseType* basePtr; std::function<BaseType*()> cloneFunc;public: PolyPtr() { basePtr = nullptr; } PolyPtr(const PolyPtr &pCopyFrom) { basePtr = pCopyFrom.cloneFunc(); } ~PolyPtr() { clear(); } BaseType* get() { return basePtr; } template <typename DerivedType> DerivedType* getDerived() { DerivedType* derivedPtr = dynamic_cast<DerivedType*>(basePtr); return (derivedPtr ? derivedPtr : nullptr); } template <typename DerivedType> void set(DerivedType pNewObject) { clear(); basePtr = new DerivedType(pNewObject); cloneFunc = [basePtr = this->basePtr]() -> DerivedType* {return new DerivedType(*static_cast<DerivedType*>(basePtr));}; } void clear() { delete basePtr; basePtr = nullptr; cloneFunc = []() -> BaseType* {return nullptr;}; }};