Usage of Derived class with the std::shared_ptr of Base class - c++

Is the following approach good?
class TA { };
class TB : TA { };
std::shared_ptr<TA> spta;
spta.reset(new TB);

There's one problem with the code shown, TB must inherit publicly from TA. You have a shared_ptr<TA>, so the pointer you want to store in it must be convertible to TA, but with private inheritance, the base is inaccessible so your code will not compile.
class TA { };
class TB : public TA { };
Beyond this, the code has no errors and is well-behaved. Typically, when you perform polymorphic deletion of a derived class instance through a base class pointer, you need the base class' destructor to be virtual so the derived class destructor is called, but in case of shared_ptr this is not necessary. shared_ptr::reset is a function template that'll accept any Y* that is convertible to the managed pointer type. The same is true for shared_ptr's constructor template.
That being said, you should prefer making the base class' destructor virtual, especially if the classes involved have other virtual functions.

No, it is not for TA is private.
Moreover, as suggested in the comments, the destructor of the base class ought to be virtual. It is usually a good practice, for you cannot guarantee that instances of your classes will be used only with shared pointers.
To have it working, you must at least modify these lines:
class TA { };
class TB : TA { };
As it follows:
class TA { virtual ~TA() { } };
class TB : public TA { };
Those ones are good as the following example is good:
class TA { virtual ~TA() { } };
class TB : public TA { };
TA *spta = nullptr;
spta = new TB;
It mainly depends on what good means for you. It's legal, at least.

This is not an answer to the question, it is an attempt to clear up any confusion about shared_ptr's seemingly magical ability to avoid the use of a virtual destructor.
Here's a little demo program:
#include <iostream>
#include <memory>
struct A {
~A() { std::cout << __func__ << std::endl; }
void foo() { do_foo(); }
protected:
virtual void do_foo() {
std::cout << "A::" << __func__ << std::endl;
}
};
struct B : A {
~B() { std::cout << __func__ << std::endl; }
virtual void do_foo() override {
std::cout << "B::" << __func__ << " ";
A::do_foo();
}
};
using namespace std;
auto main() -> int
{
std::shared_ptr<A> p = std::make_shared<A>();
p->foo();
p = std::make_unique<B>();
p->foo();
cout << "deleting B:" << endl;
return 0;
}
expected output:
A::do_foo
~A
B::do_foo A::do_foo
deleting B:
~B
~A
Notice that the correct destructor was called when the B was destroyed at the end of main().

Related

Inner class destructor is called after Base class destructor

i have a basic and simply question.
I have this scenario:
#include <iostream>
using namespace std;
class Inner1
{
public:
~Inner1() {cout << "Inner1 Des\n";};
};
class Inner2
{
public:
~Inner2() {cout << "Inner2 Des\n";};
};
class Base
{
public:
~Base() {cout << "Base Des\n";};
Inner1 inner1;
Inner2 inner2;
};
int main() {
Base base;
return 0;
}
And my console tells me now this:
Base destructor called
Inner2 destructor called
Inner1 destructor called
Is this the normal behavior? Because the functionality for some functions
is already destroyed in my Base Class destructor and the Inner classes rely
on them.
Not recommended workaround:
Just add a "Destroyer" class with object at the first position:
[...]
class Base
{
public:
~Base() {cout << "Base Des\n";};
class Destroyer
{
~Destroyer()
{
//Put the stuff here because this destr will be called last
cout << "Destroyer Des\n";
}
} _destroyer;
Inner1 inner1;
[...]
Thank you for your help
Is this the normal behavior?
Yes. Subobject destructors are called by the destructor of the container class. In particular, the subobjects will be destroyed after the body of the container classes destructor has been executed.
Because the functionality for some functions
is already destroyed in my Base Class destructor and the Inner classes rely on them.
That's only a problem if the inner classes [sic] destructors rely on the Base instance that contains them. In that case either Base should not contain them as members, or their destructor should not depend on Base.
Using this code:
#include <iostream>
class Base
{
public:
class Sub1
{
public:
Sub1()
{
std::cout << "Base::Sub1::Constructed\n";
}
~Sub1()
{
std::cout << "Base::Sub1::Destroyed\n";
}
};
class Sub2
{
public:
Sub2()
{
std::cout << "Base::Sub2::Constructed\n";
}
~Sub2()
{
std::cout << "Base::Sub2::Destroyed\n";
}
};
Sub1 sub1;
Sub2 sub2;
Base()
{
std::cout << "Base::Constructed\n";
}
~Base()
{
std::cout << "Base::Destroyed\n";
}
};
int main()
{
Base base;
}
I get (added comments manually)
> ./a.out
// Build all members first in the order they are declared.
Base::Sub1::Constructed
Base::Sub2::Constructed
// Call the constructor of the object
Base::Constructed
// Destruction happens in revers.
// Calls the destructor code to handle all local resources
Base::Destroyed
// Then destroy all members in reverse order of declaration
Base::Sub2::Destroyed
Base::Sub1::Destroyed
Class members are constructed in a sequence they are defined in class. That means,
class Demonstration
{
XClass x;
YClass y;
};
In above example, x will be constructed before y. As destruction happens in reverse order of construction, y will always be destructed before x.

Calling a member function of a derived class from the base class constructor

Suppose I have
struct C {
C() { init(); };
void init() { cout << "C" << endl; };
};
struct D : public C {
D() : C() { };
void init() { cout << "D" << endl; }
};
D();
why I get "C" printed? How can change this behaviour (and get "D").
How if I want both?
why I get "C" printed?
C::init() is not declared as virtual, so D cannot override it. But even if C::init() were declared as virtual, D::init() would still not be called when init() is called inside of C's constructor.
C++ constructs base classes before derived classes (and destructs derived clases before base classes). So C's constructor runs before D is constructed (and C's destructor runs after D is destructed). The VMT of the object being constructed/destructed simply does not point at D's method table when C is being constructed/destructed, it points at C's method table instead.
How can change this behaviour (and get "D").
You cannot call a derived virtual method from inside of a base class constructor/destructor. The VMT does not contain a pointer to the derived class method table at those stages.
You have a quite fundamental problem here: You want to call a member function of a derived class on an object that does not exist yet.
Remember that objects are constructed by first constructing the base sub-object and then the derived object. So even if you'd manage to apply a “clever” trick to actually invoke the derived class' init function, as soon as that function would try to access any data member of the derived object, it would cause arbitrary damage. On the other hand, it is fine to access only the base object, as long as you don't rely on any invariant that the constructor has not established yet. Therefore, if you don't need access to the derived object's data, you can make the init function static and pass it a reference to the base class object.
Maybe this is coming close to what you are trying to do.
#include <iostream>
struct Base
{
Base(void (*fp)(Base&) = Base::init) { fp(*this); }
static void init(Base&) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
struct Derived : Base
{
Derived() : Base(Derived::init) { }
static void init(Base&) { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
int
main()
{
Base b {};
std::cout << std::endl;
Derived d {};
}
Output:
static void Base::init(Base&)
static void Derived::init(Base&)
Here, the base class constructor takes a function pointer to an initializer function that takes a reference to a Base object. The function defaults to Base::init but derived classes can replace it. Be aware, however, that in this design, the Base class constructor may not safely assume that any side effect of Base::init actually took place. It is fine as an extension mechanism (if Base::init does nothing or is disposable), though.
But I doubt that you need to use this kind of machinery. If all you want to do – and this should be the normal case – is to first initialize the base object and then the derived object, C++ already will do the right thing by default if you simply call the functions from the respective constructors.
struct Base
{
Base() { this->init(); }
void init() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
struct Derived : Base
{
Derived() { this->init(); }
void init() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
// main() as above ...
Output:
void Base::init()
void Base::init()
void Derived::init()
And if we only want to call the most derived class' init function, we can simply tell the base class not to run its own.
struct Base
{
Base(const bool initialize = true) { if (initialize) this->init(); }
void init() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
struct Derived : Base
{
Derived() : Base(false) { this->init(); }
void init() { std::cout << __PRETTY_FUNCTION__ << std::endl; }
};
// main() as above ...
Output:
void Base::init()
void Derived::init()
You only can remove init() from C constructor to not print "C".
To also print "D" add init() in D() constructor.
If for some cases you want print "C" or "D" and in some don't do something like this
struct C {
C() { };
void init() { cout << "C" << endl; };
};
struct D : public C {
D() : C()
{
if(some condition)
C::init();
if(some condition)
init();
};
void init() { cout << "D" << endl; }
};
D();

Using shared_ptr with multi inheritance class

I have an class which inherit two interfaces:
class Multi : public IFoo, public IBar {
public:
virtual ~Multi();
// Foo part
virtual void fooMethod();
// ...
// Bar part
virtual void barMethod();
// ...
};
Unfortunately this class cannot be decomposed in two separate classes for each interface. In fact in class implementation those entities (Foo and Bar) are tightly coupled, but in future they could become separate.
Another one class wants to use Multi class, having a pointer to IFoo and IBar:
class ClientClass {
public:
ClientClass(); // constructor
// smth
private:
std::shared_ptr<IFoo> foo_;
std::shared_ptr<IBar> bar_;
};
In constructor I do something like:
ClientClass::ClientClass(){
auto pMulti = new Multi;
foo_ = std::shared_ptr<IFoo>(pMulti);
bar_= std::shared_ptr<IBar>(pMulti);
}
But each of those shared pointers has separate reference counter, and it leads to deleting already deleted pointer on class destruction, am I right?
How should I treat it?
What is best practics for such case?
ClientClass::ClientClass()
{
auto pMulti = std::make_shared<Multi>();
foo_ = pMulti;
bar_ = pMulti;
}
would ensure that they have the same reference counter. You can see it for yourself:
#include <iostream>
#include <memory>
class Base1{};
class Base2{};
class Derived : public Base1, public Base2 {};
int main()
{
auto derived = std::make_shared<Derived>();
std::shared_ptr<Base1> base1 = derived;
std::shared_ptr<Base2> base2 = derived;
std::cout << "base1 usecount = " << base1.use_count() << '\n';
std::cout << "base2 usecount = " << base2.use_count() << '\n';
std::cout << "derived usecount = " << derived.use_count() << '\n';
return 0;
}
produces:
base1 usecount = 3
base2 usecount = 3
derived usecount = 3
I don't know exactly what you want to do with those pointers, but an alternative solution may be to store a std::unique_ptr<multi> multi_; and have a couple of interface functions that static cast it to plain pointers or to references:
IFoo& ClientClass::get_ifoo() {
return *(static_cast<IFoo*>(multi_.get()));
}
IBar& ClientClass::get_ibar() {
return *(static_cast<IBar*>(multi_.get()));
}
As long as you don't pass those out from the class, and don't call delete[] on them it should be quite safe.

Override pointer-to-member-function

I have these two classes:
class A {
public:
A() { m_ptr = NULL; }
void (*m_ptr)();
void a() { if (m_ptr) m_ptr(); }
};
class B : public A {
public:
B() { m_ptr = b; }
void b() {
std::cout << "B::b() is called" << std::endl;
}
};
And I want to use them like this:
B b;
b.a();
and get the following to be called B::b().
Of course this is not being compiled as B::b is not of type void(*)().
How can I make it work?
UPDATE. To whom who asks "why?" and "what for?".
The class A is a very basic class which has many successors in production code. The class B is 6-th successor and I want to extend A (the most convinient place) to call there one more method (from B) which can be present and may be not in another successors af A and B.
A virtual method with empty body can be employed for that but it is ugly and I want to avoid it. Abstract method even more so (because of existing derived successors code).
I don't want to use external function of type void (*)() to not loose access to internal data of all hierarchy.
You can't make it work as your classes are defined now.
Calling a non-static member function of another class requires an instance of that class. You either need to store a reference to the object that owns the member function when storing the function pointer, or pass a reference to the object when you make the call to A::a.
You also need to declare m_ptr with the type void (B::*)(), which is pointer to member of B that is a function taking no parameters and returning void.
Look at this example:
class A {
public:
A() { m_ptr = nullptr; }
void a(B& b) { if (m_ptr) (b.*m_ptr)(); } // Now takes reference to B object.
void (B::*m_ptr)(); // Pointer to member function of B.
};
class B : public A {
public:
B() { m_ptr = &B::b; } // Adress of qualified function.
void b() {
std::cout << "B::b() is called" << std::endl;
}
};
Now we can call B::b like this:
B b;
b.a(b); // Pass reference to b when calling.
Your use of inheritence in this way is confusing as it implies that the real problem you are trying to solve is to invoka a member of a derived class through the base class. This is usually accomplished using a simple virtual function like this:
class A {
public:
virtual ~A() {}
void a() const { b(); } // Call b.
private:
virtual void b() const {}
};
class B : public A {
public:
virtual void b() const override { // C++11 override specifier (optional).
std::cout << "B::b() is called" << std::endl;
}
};
And used like this:
B b;
b.a(); // B::b is called.
Well, probably not the purpose of this exercise, but you can simply declare static void b() if you want to make it work.
Another option is to declare friend void b(), but then the "B::b() is called" printout would be stating a wrong fact.
I would suggest using CRTP since you want to avoid virtual mechanism. Note, however, your code might require some design changes to accommodate this pattern. But it does provide type safety and has no run-time overhead. Hope it helps.
Code on ideone.com:
#include <iostream>
#include <type_traits>
namespace so {
class B;
template<typename T>
class A {
public:
template<typename U = T, typename = typename std::enable_if<std::is_same<U, B>::value>::type>
void foo_A() {
std::cout << "foo_A : ";
static_cast<U *>(this)->foo_B();
}
};
class B: public A<B> {
public:
void foo_B() {
std::cout << "foo_B" << std::endl;
}
};
class C: public A<C> {
public:
void foo_C() {
std::cout << "foo_C" << std::endl;
}
};
} // namespace so
int main() {
so::B b_;
so::C c_;
b_.foo_A();
b_.foo_B();
//c_.foo_A(); Compile error: A<C>::foo_A() does not exist!
c_.foo_C();
return (0);
}
Program output:
foo_A : foo_B
foo_B
foo_C

default virtual d'tor

Let us assume I have two classes:
class Base{};
class Derived: public Base{};
none has d'tor, in this case if I declare about variables:
Base b;
Derived d;
my compiler will produce for me d'tors, my question is, the default d'tors of the b and d will be virtual or not?
my question is, the d'tors of the b and d will be virtual or not
No, they won't. If you want a virtual destructor, you will have to define your own, even if its implementation is exactly the same as that which would be supplied by the compiler:
class Base {
public:
virtual ~Base() {}
};
The destructors of Base and Derived will not be virtual. To make a virtual destructor you need to mark it up explicitly:
struct Base
{
virtual ~Base() {}
};
Actually there's now only one reason to use virtual destructors. That is to shut up the gcc warning: "class 'Base' has virtual functions but non-virtual destructor". As long as you always store your allocated objects in a shared_ptr, then you really don't need a virtual destructor. Here's how:
#include <iostream> // cout, endl
#include <memory> // shared_ptr
#include <string> // string
struct Base
{
virtual std::string GetName() const = 0;
};
class Concrete : public Base
{
std::string GetName() const
{
return "Concrete";
}
};
int main()
{
std::shared_ptr<Base> b(new Concrete);
std::cout << b->GetName() << std::endl;
}
The shared_ptr will clean up correctly, without the need for a virtual destructor. Remember, you will need to use the shared_ptr though!
Good luck!
my question is, the d'tors of the b and d will be virtual or not
Short answer : Nopes!
They will NOT be virtual.However, if you declared(and defined) a virtual dtor in Base, then the derived's dtor would be automatically virtual. HTH.
How can they be virtual unless you explicitly make them as virtual
Just to add one more example to Daniel Lidström's answer
As long as you always store your allocated objects in a shared_ptr, then you really don't need a virtual destructor.
If one uses a shared_ptr like this:
std::shared_ptr<Base> b(new Concrete);
Then the Concrete destructor and the Base destructor are called on destruction of the object.
If one uses a shared_ptr like this:
Base* pBase = new Concrete;
std::shared_ptr<Base> b(pBase);
Then only the Base destructor is called on destruction of the object.
This is an example
#include <iostream> // cout, endl
#include <memory> // shared_ptr
#include <string> // string
struct Base
{
virtual std::string GetName() const = 0;
~Base() { std::cout << "~Base\n"; }
};
struct Concrete : public Base
{
std::string GetName() const
{
return "Concrete";
}
~Concrete() { std::cout << "~Concrete\n"; }
};
int main()
{
{
std::cout << "test 1\n";
std::shared_ptr<Base> b(new Concrete);
std::cout << b->GetName() << std::endl;
}
{
std::cout << "test 2\n";
Base* pBase = new Concrete;
std::shared_ptr<Base> b(pBase);
std::cout << b->GetName() << std::endl;
}
}