Virtual destructor of an inherited template class - c++

Can any one explain how delete x works correctly without virtual ~X()
#include <iostream>
struct B
{
B()
{
std::cout << "B()" << std::endl;
}
virtual ~B()
{
std::cout << "~B()" << std::endl;
}
};
struct C : B
{
C()
{
std::cout << "C()" << std::endl;
}
virtual ~C()
{
std::cout << "~C()" << std::endl;
}
};
template <class T>
struct X : T
{
X()
{
std::cout << "X()" << std::endl;
}
~X()
{
std::cout << "~X()" << std::endl;
}
};
template <class T>
struct Y : X<T>
{
Y()
{
std::cout << "Y()" << std::endl;
}
~Y()
{
std::cout << "~Y()" << std::endl;
}
};
int main()
{
std::cout << "====" << std::endl;
{
B* b = new C;
delete b;
}
std::cout << "====" << std::endl;
{
X<C>* x = new Y<C>;
delete x;
}
std::cout << "====" << std::endl;
return 0;
}
Output:
====
B()
C()
~C()
~B()
====
B()
C()
X()
Y()
~Y()
~X()
~C()
~B()
====

It is virtual – X<C> inherits C, the root of the hierarchy is B, and the destructor is declared virtual in B.
The class templating is completely irrelevant; it works exactly as it would if you had
struct X : C
{
X() { std::cout << "X()" << std::endl; }
~X() { std::cout << "~X()" << std::endl; }
};
struct Y : X
{
Y() { std::cout << "Y()" << std::endl; }
~Y() { std::cout << "~Y()" << std::endl; }
};
and
X* x = new Y;
delete x;

Related

Using shared_from_this() with derived class

When I try to run this code:
class A : public enable_shared_from_this<A> {
public:
A() {
cout << "A::A()" << endl;
};
virtual ~A() {
cout << "A::~A()" << endl;
};
virtual void func() {
cout << "A::func" << endl;
auto ptr = shared_from_this();
ptr->dosomething();
}
virtual void dosomething() {
cout << "A::dosomething" << endl;
}
};
class B : public A {
public:
B() {
cout << "B::B()" << endl;
};
~B() {
cout << "B::~B()" << endl;
};
void func() override {
cout << "B::func" << endl;
A::func();
}
void dosomething() override {
cout << "B::dosomething" << endl;
}
};
int main() {
shared_ptr<B> pb = make_shared<B>();
//shared_ptr<A> pa = make_shared<A>();
pb->func();
}
The result I get is:
A::A()
B::B()
B::func
A::func
B::dosomething
B::~B()
A::~A()
The call chain is B::func->A::func->ptr->dosomething, this indicates that the return value of shared_from_this() is a shared_ptr<B>.
Why is the result of calling shared_from_this() not shared_ptr<A>?

Static Cast to CRTP Interface [duplicate]

This question already has answers here:
What is object slicing?
(18 answers)
Closed 1 year ago.
I am building up a CRTP interface and noticed some undefined behavior. So, I built up some sample code to narrow down the problem.
#include <iostream>
template <typename T>
class Base {
public:
int a() const { return static_cast<T const&>(*this).a_IMPL(); }
int b() const { return static_cast<T const&>(*this).b_IMPL(); }
int c() const { return static_cast<T const&>(*this).c_IMPL(); }
};
class A : public Base<A> {
public:
A(int a, int b, int c) : _a(a), _b(b), _c(c) {}
int a_IMPL() const { return _a; }
int b_IMPL() const { return _b; }
int c_IMPL() const { return _c; }
private:
int _a;
int _b;
int _c;
};
template <typename T>
void foo(const T& v) {
std::cout << "foo()" << std::endl;
std::cout << "a() = " << static_cast<Base<T>>(v).a() << std::endl;
std::cout << "b() = " << static_cast<Base<T>>(v).b() << std::endl;
std::cout << "c() = " << static_cast<Base<T>>(v).c() << std::endl;
}
int main() {
A v(10, 20, 30);
std::cout << "a() = " << v.a() << std::endl;
std::cout << "b() = " << v.b() << std::endl;
std::cout << "c() = " << v.c() << std::endl;
foo(v);
return 0;
}
The output of this code is:
a() = 10
b() = 20
c() = 30
foo()
a() = 134217855
b() = 0
c() = -917692416
It appears that there is some problem when casting the child class, which implements the CRTP "interface", to the interface itself. This doesn't make sense to me because the class A plainly inherits from Base so, shouldn't I be able to cast an instance of A into Base?
Thanks!
You copy and slice when you cast to Base<T>.
Cast to a const Base<T>& instead:
std::cout << "a() = " << static_cast<const Base<T>&>(v).a() << std::endl;
std::cout << "b() = " << static_cast<const Base<T>&>(v).b() << std::endl;
std::cout << "c() = " << static_cast<const Base<T>&>(v).c() << std::endl;
It turns out I was casting incorrectly to a value rather than a reference
std::cout << "a() = " << static_cast<Base<T>>(v).a() << std::endl;
should become
std::cout << "a() = " << static_cast<const Base<T>&>(v).a() << std::endl;

Inherited class's constructor is not running

I have 3 classes, A,B, and C.
Edited code.
#include <iostream>
class A {
public:
virtual void print() {
std::cout << "A" << std::endl;
}
A() : x(0) {} // constructor
void SetX (int tmp){
x = tmp;
}
void printX() {
std::cout << "x = " << x << std::endl;
}
private:
int x;
};
class B : public A {
public:
virtual void print(){
std::cout << "B" << std::endl;
}
B(int tmp) : A() {
SetX(tmp);
}
};
class C : public B {
public:
virtual void print(){
std::cout << "C" << std::endl;
}
C(int tmp) : B(tmp) {
std::cout << "Debug print" << std::endl;
}
};
int main() {
B* b = new B(1);
C* c = new C(2);
b->print();
b->printX();
c->print();
c->printX();
return 0;
}
print for b->printX = 1
and for c->printX = 0
when creating object B everything is work just fine.
but when creating object C the default value of class A (var x) is still 0 (default value).
i added debug line inside the constructor of class C, but i didnt see it in logs, looks like the constructor is not running. i did the same thing in the constructor of class B when creating only object C and i didnt see any debug print too.
There no any compiling error for this code. build finish successfully.
The following is legal and working C++. Your code was not legal C++.
I added a void printX() method to class A to illustrate the example.
#include <iostream>
class A {
public:
virtual void print() {
std::cout << "A" << std::endl;
}
A() : x(0) {} // constructor
void SetX (int tmp){
x = tmp;
}
void printX() {
std::cout << "x = " << x << std::endl;
}
private:
int x;
};
class B : public A {
public:
virtual void print(){
std::cout << "B" << std::endl;
}
B(int tmp) : A() {
SetX(tmp);
}
};
class C : public B {
public:
virtual void print(){
std::cout << "C" << std::endl;
}
C(int tmp) : B(tmp) {
std::cout << "Debug print" << std::endl;
}
};
int main() {
B* b = new B(1);
C* c = new C(2);
b->print();
b->printX();
c->print();
c->printX();
return 0;
}

Does std::any_cast call destructor? How the cast works?

#include <iostream>
#include <any>
using namespace std;
class c {
public:
c() :a{ 0 } { cout << "constructor\n"; }
c(int aa) :a{ aa } { cout << "Constructor\n"; }
~c() { cout << "destructor\n"; }
int get() { return a; }
private:
int a;
};
auto main()->int
{
any a{ 5 };
cout << any_cast<int>(a) << '\n';
a.emplace<c>(3);
cout << '!' << any_cast<c>(a).get() << '\n';
//des
cout << '\n';
a.emplace<c>(9);
cout << '!' << any_cast<c>(a).get() << '\n';
//des
}
destructor called after each any_cast.
and, below code makes run-time error.
I think the cause is any_cast(C)'s work pipeline is might be like
~C() then X(C) ERROR!!C doesn't exist
any_cast really work like that?
I add blow codes and make run-time error.
class X {
public:
X() :a{ 0 } { cout << "xonstructor\n"; }
X(c& aa) :a{ aa.get() } { cout << "Xonstructor\n"; }
~X() { cout << "Xdestructor\n"; }
int get() { return a; }
private:
int a;
};
auto main()->int
{
any a{ 5 };
cout << any_cast<int>(a) << '\n';
a.emplace<c>(3);
cout << '!' << any_cast<X>(a).get() << '\n';
//runtime error after '!'
cout << '\n';
a.emplace<c>(9);
cout << '!' << any_cast<X>(a).get() << '\n';
}
You are copying a c (or X) from the one within the std::any. That copy is destroyed at the end of the expression, after having been streamed out.
any_cast does not do any conversion. It throws if you ask it for a type different to the one it stores. When you have emplaced a c and asked for an X, it throws std::bad_any_cast, because X is not c.

C++ virtual destructor

The question is based on following class hierarchy.
Base2* d3 = new Der3();
d3->v1();
delete d3;
The output is :
Base1
Base1
Der1
Base2
Der3
v1 Base2
~Base2
And I get an exception.Why?(It only should generate memory leack)
class Base1
{
public:
Base1() {std::cout << "Base1" << std::endl; }
~Base1() {std::cout << "~Base1" << std::endl; }
virtual void v1() { std::cout << "v1 Base1" << std::endl; }
void v2() {std::cout << "v2 Base1" << std::endl;}
void v3() {std::cout << "v3 Base1" << std::endl;}
};
class Base2
{
public:
Base2() {std::cout << "Base2" << std::endl; }
~Base2() {std::cout << "~Base2" << std::endl; }
void v1() { std::cout << "v1 Base2" << std::endl; }
void v2() {std::cout << "v2 Base2" << std::endl;}
void v3() {std::cout << "v3 Base2" << std::endl;}
};
class Der1 : public Base1
{
public:
Der1() {std::cout << "Der1" << std::endl; }
~Der1() {std::cout << "~Der1" << std::endl; }
virtual void v1() { std::cout << "v1 Der1" << std::endl; }
virtual void v2() {std::cout << "v2 Der1" << std::endl;}
void v3() {std::cout << "v3 Der1" << std::endl;}
};
class Der2 : public Base1,public Der1
{
public:
Der2() {std::cout << "Der2" << std::endl; }
~Der2() {std::cout << "~Der2" << std::endl; }
virtual void v1() { std::cout << "v1 Der2" << std::endl; }
void v2() {std::cout << "v2 Der2" << std::endl;}
void v3() {std::cout << "v3 Der2" << std::endl;}
};
class Der3 : public Base1,public Der1,public Base2
{
public:
Der3() {std::cout << "Der3" << std::endl; }
~Der3() {std::cout << "~Der3" << std::endl; }
virtual void v1() { std::cout << "v1 Der3" << std::endl; }
void v2() {std::cout << "v2 Der3" << std::endl;}
void v3() {std::cout << "v3 Der3" << std::endl;}
};
Why do you say you should only get a memory leak? It's undefined behavior; anything can happen.
The problem is probably because the virtual destructor also serves to determine the deallocation function and the address to pass to it. In your case, you end up passing the wrong address to ::operator delete. But that's just what is probably happening in practice. It's undefined behavior, and anything can happen.
If you plan to derive from a class and use a pointer to a base class to delete the object, you must declare it's destructor virtual. Otherwise, it is undefined behavior.
class A
{
public:
~A() {}
...
};
class B : public A
{
public:
~B() {}
...
};
class C
{
public:
virtual ~C() {}
...
};
class D : public C
{
public:
virtual ~D() { }
...
};
B b; // OK, but bad practice
A* pa = new B; // not ok - when you try to delete
C* pc = new D; // ok