I was practicing static_cast and dynamic_cast on polymorphic classes in C++. I tried it using both raw pointers and unique_ptr. While the former doesn't create problems, the later does. Here I present my code:-
#include <iostream>
#include <memory>
#include <exception>
#include <stdexcept>
using namespace std;
class A
{
int a, id=0;
static int i;
public:
A()
{
id=++i;
cout<<"constructing A: "<<id<<"\n";
}
virtual void get()
{
cout<<"enter a: ";
cin>>a;
}
virtual void disp()
{
cout<<"a = "<<a<<"\n";
}
virtual ~A()
{
cout<<"destroying A: "<<id<<"\n";
}
};
int A::i=0;
class B: public A
{
int b;
public:
B()
{
cout<<"constructing B\n";
}
void get()
{
cout<<"enter b: ";
cin>>b;
}
void disp()
{
cout<<"b = "<<b<<"\n";
}
~B()
{
cout<<"destroying B\n";
}
};
void show (unique_ptr<B> &p)
{
p->get();
p->disp();
}
void d_cast (unique_ptr<A> &pa)
{
unique_ptr<B> pb;
try
{
pb.reset(dynamic_cast<B*>(pa.release()));
if (pb==nullptr)
throw runtime_error {"nullptr exception"};
show(pb);
cout<<"dynamic_cast successful\n\n";
}
catch (exception &e)
{
cout<<"dynamic_cast unsuccessful: "<<e.what()<<"\n\n";
}
pa.reset(pb.release());
}
void s_cast (unique_ptr<A> &pa)
{
unique_ptr<B> pb;
try
{
pb.reset(static_cast<B*>(pa.release()));
if (pb==nullptr)
throw runtime_error {"nullptr exception"};
show(pb);
cout<<"static_cast successful\n\n";
}
catch (exception &e)
{
cout<<"static_cast unsuccessful: "<<e.what()<<"\n\n";
}
pa.reset(pb.release());
}
int main()
{
cout<<R"(using "unique_ptr<A> pa with new A" :-)"<<"\n\n";
unique_ptr<A> pa(new A); // (1)
d_cast(pa);
s_cast(pa); // (2)
cout<<"\n"<<R"(using "unique_ptr<A> pa with new B" :-)"<<"\n\n";
pa.reset(new B);
d_cast(pa);
s_cast(pa);
return 0;
}
The output of the code is:-
using "unique_ptr<A> pa with new A" :-
constructing A: 1
dynamic_cast unsuccessful: nullptr exception
static_cast unsuccessful: nullptr exception
using "unique_ptr<A> pa with new B" :-
constructing A: 2
constructing B
enter b: 7
b = 7
dynamic_cast successful
enter b: 8
b = 8
static_cast successful
destroying B
destroying A: 2
I have only 2 questions as I have marked already:-
Why isn't the first object {denoted by (1)} destroyed whereas the one called with "new B" is destroyed ?
Why is (2) throwing the exception ? Interestingly if i reverse the positioning of
s_cast(pa)
andd_cast(pa)
then (2) doesn't throw any exception and works fine (problem (1) still persists however).
Ok ! So you need to change your function
d_cast
function definition like this:-As you must be knowing the
d_cast
would fail and thus the expression ofdynamic_cast<B*>(pointer_of_type_A)
would returnnullptr
. If there would have been a reference instead of pointer thenstd::bad_cast
exception would be thrown. But because you are using therelease()
function, the unique_ptr objectpa
gets rid of the ownership of the pointer and there is no object or pointer to trace it back. Thus you should useA *aptr
to hold the released pointer and return it topa
if the casting fails.If you do so, your both problems are solved