I am trying to overload the == operator for a class Structure, which is a multi-type container. My approach for other operations has been to have an empty virtual function in the Structure class and override it in the derived Element template class.
This is because, when adding the elements to the vector, I am wrapping them into Element and storing them in the vector as StructPtrs. In order to know the type of each StructPtr, I must do the above (I cannot use dynamic_cast) because it will only know its type when it calls on the overridden function in the Element class.
class Structure;
using StructPtr = std::shared_ptr<Structure>;
template<class T>
class Element;
// Make sure to define your printElement function, too.
void printElement(std::ostream& out, const Structure& s);
// Define your `Structure` class here
class Structure{
public:
Structure() = default;
virtual ~Structure() = default;
Structure(const Structure& oldStruct){
for(auto element : oldStruct.elements)
elements.emplace_back(element->getCopy());
}
Structure operator = (const Structure& otherStruct){
if(this == &otherStruct)
return *this;
if(elements.size() != otherStruct.elements.size()){
elements.clear();
}
std::copy(otherStruct.elements.begin(), otherStruct.elements.end(), std::back_inserter(elements));
return *this;
}
bool operator == (const Structure& other) const{
if(elements.empty() && other.elements.empty())
return true;
bool result = false;
for(int i = 0; i < other.elements.size(); i++){
if(elements[i]->equals(*(other.elements[i])))
result = true;
else result = false;
}
return result;
}
virtual bool equals( Structure& otherStruct) const { }
template<class T>
void add(T obj){
elements.emplace_back(std::make_shared<Element<T>>(obj));
}
virtual StructPtr getCopy() const {}
virtual void printDerived(std::ostream& out) const{}
void print(std::ostream& out) const{
for(auto element : elements)
element->printDerived(out);
}
std::vector<StructPtr> elements;
};
template<class T>
class Element : public Structure{
public:
Element() = default;
//Element(int element) : element(element) { }
//Element(Structure element) : element(element) { }
//Element(std::string element) : element(element) { }
Element(T _element) : element(_element) { }
Element( const Element<T>& oldElement){
element = oldElement.element;
}
bool equals ( Structure& otherStruct) const override{
if constexpr (std::is_same_v<T, Structure>){
return element == otherStruct;
}
auto other = static_cast<Element&>(otherStruct);
return element == other.element;
}
StructPtr getCopy() const override {
StructPtr newStructPtr;
if constexpr (std::is_same_v<T, Structure>){
Structure newStruct(*this);
newStructPtr = std::make_shared<Element<T>>(newStruct);
}
else
newStructPtr = std::make_shared<Element<T>>(*this);
return newStructPtr;
}
void printDerived(std::ostream& out) const override {
printElement(out, element);
}
T element;
};
void printElement(std::ostream& out, const Structure& s){
s.print(out);
}
The problem is, for ==, it has a structure in the function argument. This approach does not work, because when I pass this as an argument down to the Element class, it is still a Structure and not an Element.
Right now, my code works for every test case, except for the case of nested structures. When I try to compare two structures with other structures in them, I get this error:
AddressSanitizer:DEADLYSIGNAL
=================================================================
==26776==ERROR: AddressSanitizer: SEGV on unknown address 0x000104fbffb8 (pc 0x00010423ec88 bp 0x00010423ec64 sp 0x00016bbc79d0 T0)
==26776==The signal is caused by a UNKNOWN memory access.
Why is my code resulting in this error, and how do I fix it?
Your operator== is doing the right thing by using a virtual equals() method, however the rest of it is not implemented correctly. You are treating the result variable the wrong way, and worse the code has undefined behavior if the two vectors have different sizes. Try this instead:
class Structure{
public:
...
bool operator == (const Structure& other) const {
if (elements.size() != other.elements.size())
return false;
for(size_t i = 0; i < other.elements.size(); ++i) {
if (!elements[i]->equals(*(other.elements[i])))
return false;
}
return true;
}
...
};
Now, that being said, you can't make Element::equals() accept an Element when you are calling it polymorphically from Structure, like you are asking for (at least, not without casting).
But, what you can do (and need to do) is make Element::equals() check if the input Structure is actually an Element or not. You have to do that anyway so that you can differentiate between Element<X> and Element<Y> when X and Y are different types. The way you are using static_cast is not doing that validation, so you will have undefined behavior when you cast to the wrong type. And you can't do the check with std::is_same_v (a compile-time check), either. You must use dynamic_cast (a runtime check), eg:
template<class T>
class Element : public Structure{
public:
...
bool equals (const Structure& otherStruct) const override {
if constexpr (std::is_same_v<T, Structure>){
return element == otherStruct;
}
else {
auto other = dynamic_cast<const Element<T>*>(&otherStruct);
return (other && element == other->element);
}
}
...
};
However, since you say you can't use dynamic_cast (why?), you will just have to tag every Element based on which T it is created with, and then you can compare the tags for equality before casting, eg:
#include <typeinfo>
template<class T>
class Element : public Structure{
public:
...
const std::type_info& getTypeInfo() const {
return typeid(T);
}
bool equals (const Structure& otherStruct) const override {
if constexpr (std::is_same_v<T, Structure>){
return element == otherStruct;
}
else if (getTypeInfo() == otherStruct.getTypeInfo()) {
return element == static_cast<const Element<T>&>(otherStruct).element;
}
else
return false;
}
...
};
Related
I am building an add-in for a program. My add-in manipulates Ptr objects passed to me by the host application. I would like to create a vector of externally created and managed objects by the host. Unfortunately, the documentation doesn't have any clear examples of how to do this.
class Players {
vector<Ptr<Player>> vectorOfGamers; // who deletes and when this?
public void CreatePlayers () {
// call static application to create three players
for ( int i = 0; i < 3; i++ )
vectorOfGamers.push_back(Application.GetNextPlayer());
}
}
Confused about how to build this class and prevent memory leaks and causing a null exception if items are deleted prematurely. Also, how do I use modern C++ facilities to achieve this yet gain as much of the benefits of the new memory management like make_shared, make_unique, nullptr, etc?
For your information, below is a snapshot of Ptr.I am confused about the Ptr as it appears superfluous given modern C++'s new memory management facilities.
class IncompleteType
{
public:
template<typename T> static void addref(void* ptr) { reinterpret_cast<adsk::core::ReferenceCounted*>(ptr)->addref(); }
template<typename T> static void release(void* ptr) { reinterpret_cast<adsk::core::ReferenceCounted*>(ptr)->release(); }
};
class CompleteType
{
public:
template<typename T> static void addref(T* ptr) { ptr->addref(); }
template<typename T> static void release(T* ptr) { ptr->release(); }
};
template<class T, class PT = IncompleteType>
class Ptr
{
public:
typedef T element_type;
Ptr() : ptr_(nullptr) {}
Ptr(const Ptr& rhs) : ptr_(nullptr) { reset(rhs.ptr_); }
Ptr(const T* ptr, bool attach = true) : ptr_(nullptr) { reset(ptr, attach); }
// casting constructor. call operator bool to verify if cast was successful
template<class V, class VPT>
Ptr(const Ptr<V, VPT>& rhs) : ptr_(nullptr) {
if (rhs)
reset(rhs->template query<T>(), false);
}
~Ptr() { reset(nullptr); }
void operator=(const Ptr<T, PT>& rhs) { if (&rhs != this) reset(rhs.ptr_); }
void operator=(const T* ptr) { reset(ptr, true); }
// casting assignment operator. call operator bool to verify if cast was successful
template<class V, class VPT>
void operator=(const Ptr<V, VPT>& rhs) {
if (rhs)
reset(rhs->template query<T>(), false);
else
reset(nullptr);
}
void reset(const T* ptr, bool attach = false) {
if (ptr_ != ptr)
{
if (ptr_)
PT::template release<T>(ptr_);
ptr_ = const_cast<T*>(ptr);
if (!attach && ptr_)
PT::template addref<T>(ptr_);
}
}
T* operator->() const { assert(ptr_ != nullptr); if (ptr_ == nullptr) throw std::exception(); return ptr_; }
// Test if this pointer is empty (if operator-> will throw)
/*explicit*/ operator bool() const { return ptr_ != nullptr; }
bool operator==(const Ptr& rhs) const { return ptr_ == rhs.ptr_; }
bool operator!=(const Ptr& rhs) const { return ptr_ != rhs.ptr_; }
bool operator<(const Ptr& rhs) const { return ptr_ < rhs.ptr_; }
// Iteration support. Only usable if T has count and item members and an iterable_type
typedef Iterator<T, PT> iterator;
iterator begin() const { return Iterator<T, PT>(*this); }
iterator end() const { return Iterator<T, PT>(*this, true); }
// Caution the following functions if used incorrectly can cause a reference count leak
T* get() const { return ptr_; }
T* detach() { T* t = ptr_; ptr_ = nullptr; return t; }
private:
T* ptr_;
};
You’re probably right that Ptr wouldn’t be needed in a post-C++03 environment. Probably your plugin API is old enough that C++11 wasn’t around back then. From the code you posted my best guess is that Ptr is supposed to be a reference counted smart pointer that manages shared ownership like std::shared_ptr does.
How exactly you use that thing should become clear from the plguin API documentation and maybe the source code of your host program. Just from the snippet you posted and without even mentioning the program’s name it’s impossible to say anything definite.
Recently I tried to implement my own version of a smart pointer. The implementation looks a bit like the following:
class Var {
private:
void* value;
unsigned short* uses;
public:
Var() : value(nullptr), uses(new unsigned short(1)) { }
template<typename K>
Var(K value) : value((void*)new K(value)), uses(new unsigned short(1)) { }
Var(const Var &obj) {
value = obj.value;
(*(uses = obj.uses))++;
}
~Var() {
if (value == nullptr && uses == nullptr) return;
if (((*uses) -= 1) <= 0) {
delete value;
delete uses;
value = uses = nullptr;
}
}
Var& operator=(const Var& obj) {
if (this != &obj) {
this->~Var();
value = obj.value;
(*(uses = obj.uses))++;
}
return *this;
}
};
The implementation should be straight forward, as value holds the pointer and uses counts the references.
Please note the pointer is stored as a void* and the pointer class is not fixed to certain (generic) type.
The Problem
Most of the time the smart pointer does it's job... the exception being the following:
class C {
public:
Var var;
C(Var var) : var(var) {}
};
void test() {
std::string string = std::string("Heyo");
Var var1 = Var(string);
C c = C(var1);
Var var2 = Var(c);
}
void main() {
test();
}
When running that code the very first instance, var1, does not get deleted after test has run.
Yes, using a void* is not exactly the finest of methods. Yet lets not get off topic. The code compiles perfectly fine (if one might question my use of sub-assign operator). And if the error would be in the deletion of a void* the reference counter, uses, would be deleted but it is not.
I have checked with the destructors before and they all get called as they should.
Do also note that the programm runs without errors.
Thank You all in advance,
Sheldon
Three big problems I see with your code are:
you are storing the allocated object pointer as a void*, and then calling delete on it as-is. That will not call the object's destructor. You must type-cast the void* back to the original type before calling delete, but you can't do since you have lost the type info after the Var constructor exits.
you have separated the object pointer and the reference counter from each other. They should be kept together at all times. Best way to do that is to store them in a struct, and then allocate and pass that around as needed.
your operator= is calling this->~Var(), which is completely wrong. Once you do that, the object pointed to by this is no longer valid! You need to keep the instance alive, so simply decrement its current reference counter, freeing its stored object if needed, and then copy the pointers from the source Var and increment that reference counter.
Try this alternate implementation instead (Live Demo):
class Var
{
private:
struct controlBlockBase
{
unsigned short uses;
controlBlockBase() : uses(1) { }
virtual ~controlBlockBase() { }
};
template <class K>
struct controlBlockImpl : controlBlockBase
{
K value;
controlBlockImpl(const K &val) : controlBlockBase(), value(val) {}
};
controlBlockBase *cb;
public:
Var() : cb(nullptr) { }
template<typename K>
Var(const K &value) : cb(new controlBlockImpl<K>(value)) { }
Var(const Var &obj) : cb(obj.cb) {
if (cb) {
++(cb->uses);
}
}
Var(Var &&obj) : cb(nullptr) {
obj.swap(*this);
}
~Var() {
if ((cb) && ((cb->uses -= 1) <= 0)) {
delete cb;
cb = nullptr;
}
}
Var& operator=(const Var& obj) {
if (this != &obj) {
Var(obj).swap(*this);
}
return *this;
}
Var& operator=(Var &&obj) {
obj.swap(*this);
return *this;
}
/* or, the two above operator= codes can be
merged into a single implementation, where
the input parameter is passed by non-const
value and the compiler decides whether to use
copy or move semantics as needed:
Var& operator=(Var obj) {
obj.swap(*this);
return *this;
}
*/
void swap(Var &other)
{
std::swap(cb, other.cb);
}
unsigned short getUses() const {
return (cb) ? cb->uses : 0;
}
template<class K>
K* getAs() {
if (!cb) return nullptr;
return &(dynamic_cast<controlBlockImpl<K>&>(*cb).value);
}
};
void swap(Var &v1, Var v2) {
v1.swap(v2);
}
Update: That being said, what Var is doing is basically the same effect as using a std::any wrapped in a std::shared_ptr, so you may as well just use those instead (std::any is in C++17 and higher only, use boost::any for earlier versions):
class Var
{
private:
std::shared_ptr<std::any> ptr;
public:
template<typename K>
Var(const K &value) : ptr(std::make_shared<std::any>(value)) { }
void swap(Var &other) {
std::swap(ptr, other.ptr);
}
long getUses() const {
return ptr.use_count();
}
template<class K>
K* getAs() {
return any_cast<K>(ptr.get());
}
};
void swap(Var &v1, Var &v2) {
v1.swap(v2);
}
Consider the following class that wraps a container and type-erases its type:
class C final {
struct B {
virtual bool empty() const noexcept = 0;
};
template<class T, class A>
struct D: public B {
// several constructors aimed to
// correctly initialize the underlying container
bool empty() const noexcept override { return v.empty(); }
private:
std::vector<T, A> v;
};
// ...
public:
//...
bool operator==(const C &other) const noexcept {
// ??
// would like to compare the underlying
// container of other.b with the one
// of this->b
}
private:
// initialized somehow
B *b;
};
I'd like to add the operator== to the class C.
Internally, it should simply invoke the same operator on the underlying containers, but I'm stuck on this problem, for I don't know how to do that.
The idea is that two instances of C are equal if the operator== of their underlying containers return true.
Whatever I've tried till now, I ever ended up being unable to get the type of one of the two underlying containers, mainly the one of other.
Is there an easy solution I can't see at the moment or I should give up?
Despite the good suggestion from juanchopanza, I found that, as far as the underlying containers represent the same concept (as an example, different specializations of a vector), maybe there is no need of a type-erased iterator.
Below it's a possible implementation that relies on the operator[] and the size member method:
#include <vector>
#include <cassert>
class Clazz final {
struct BaseContainer {
virtual std::size_t size() const noexcept = 0;
virtual int operator[](std::size_t) const = 0;
virtual void push_back(int) = 0;
};
template<class Allocator>
struct Container: public BaseContainer {
Container(Allocator alloc): v{alloc} { }
std::size_t size() const noexcept override { return v.size(); }
int operator[](std::size_t pos) const override { return v[pos]; }
void push_back(int e) override { v.push_back(e); }
private:
std::vector<int, Allocator> v;
};
public:
template<class Allocator = std::allocator<int>>
Clazz(const Allocator &alloc = Allocator{})
: container{new Container<Allocator>{alloc}} { }
~Clazz() { delete container; }
void push_back(int e) { container->push_back(e); }
bool operator==(const Clazz &other) const noexcept {
const BaseContainer &cont = *container;
const BaseContainer &oCont = *(other.container);
bool ret = (cont.size() == oCont.size());
for(std::vector<int>::size_type i = 0, s = cont.size(); i < s && ret; i++) {
ret = (cont[i] == oCont[i]);
}
return ret;
}
bool operator!=(const Clazz &other) const noexcept {
return !(*this == other);
}
private:
BaseContainer *container;
};
int main() {
Clazz c1{}, c2{}, c3{};
c1.push_back(42);
c2.push_back(42);
assert(c1 == c2);
assert(c1 != c3);
}
Open to criticism, hoping this answer can help other users. :-)
Assuming you wish to return false when the comparing two different containers, this should do the job (caution: untested):
class Container
{
struct Concept
{
virtual ~Concept() = default;
virtual Concept* clone() const = 0;
virtual bool equals(Concept const*) const = 0;
};
template<typename T>
struct Model final : Concept
{
Model(T t) : data{std::move(t)} {}
Model* clone() const override { return new Model{*this}; }
virtual bool equals(Concept const* rhs) const override
{
if (typeid(*this) != typeid(*rhs))
return false;
return data == static_cast<Model const*>(rhs)->data;
}
T data;
};
std::unique_ptr<Concept> object;
public:
template<typename T>
Container(T t) : object(new Model<T>{std::move(t)}) {}
Container(Container const& that) : object{that.object->clone()} {}
Container(Container&& that) = default;
Container& operator=(Container that)
{ object = std::move(that.object); return *this; }
friend bool operator==(Container const& lhs, Container const& rhs)
{ return lhs.object->equals(rhs.object.get()); }
};
I have a C datastructure representing a vector of boolean values; for reasons outside of my control the bools' are stored internally as integers with two magical values (not 0 and 1 ...) representing true and false. I have created a C++ class wrapping this C structure, and it works nicely. I have implemented the set()and get()methods as:
void Class::set(size_t index , bool value) {
if (value)
c_ptr[index] = SPECIAL_TRUE_VALUE;
else
c_ptr[index] = SPECIAL_FALSE_VALUE;
}
This works ok; but ideally I would like to overload operator[], however it is not clear to me how/if I can do that - due to special transformation between bool and the integer values?
struct pseudo_reference {
operator bool()const&&{
return c->get(index);
}
pseudo_reference operator=(bool b)&&{
c->set(index, b);
return {c,index};
}
// sometimes having named functions is useful:
bool get() const&& {
return std::move(*this);
}
void set(bool b)&& {
std::move(*this) = b;
}
pseudo_reference()=delete;
private:
Class* c;
size_t index;
pseudo_reference(pseudo_reference&&o)=default; // not exposed
pseudo_reference(Class* pc, size_t i):c(pc),index(i){}
friend class Class;
};
In Class:
pseudo_reference operator[](size_t i){
return {this, i};
}
bool operator[](size_t i)const{
return c_ptr[index] == SPECIAL_TRUE_VALUE;
}
I stored both a pointer and an index, so I avoid reimplementing the logic of get/set in my pseudo_reference. Such pseudo_references are likely to be short-lived, so size optimization probably isn't important.
I blocked all non-rvalue operations to discourage storing a pseudo_reference. You can make said operations non-rvalue restricted relatively harmlessly, but in my experience pseudo_references are values that behave like references, so it is better if they don't persist.
Someone can still store a pseudo_reference via auto&& x = c[33];, but using it without moveing it won't be possible. Hopefully that catches most error-prone uses of it. auto x = c[33]; won't work.
To implement operator[](), you need to return a proxy object that does the actual assignment when it appears on the left-hand-side of =:
struct proxy {
proxy& operator=( bool value ) {
c_.c_ptr[ index_ ] = value ? SPECIAL_TRUE_VALUE : SPECIAL_FALSE_VALUE;
return *this;
}
operator bool() const { // for when it's just used normally, not =
return c_ptr[ index ] == SPECIAL_TRUE_VALUE;
}
private:
Class &c_;
size_t const index_;
proxy( Class &c, size_t index ) : c_( c ), index_( index ) { }
friend class Class;
}
class Class {
public:
proxy operator[]( size_t index ) {
return proxy( *this, index );
}
bool operator[]( size_t index ) const { // read-only access is easy
return c_ptr[ index ] == SPECIAL_TRUE_VALUE;
}
// ...
};
Or something like that.
You can return a wrapper helper class which handles assignment for you.
struct WrapMe {
c_ptr_T &value;
WrapMe(c_ptr_T &_value) : value(_value) {}
// handles assignment of bool values
WrapMe & operator=(const bool b) {
value = (b) ? SPECIAL_TRUE_VALUE : SPECIAL_FALSE_VALUE;
return *this;
}
// handles cast to bool
operator bool() const { return value == SPECIAL_TRUE_VALUE; }
};
class Class {
WrapMe operator[](const int idx) { return WrapMe(c_ptr[idx]); }
// ...
};
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.