samedi 4 juin 2022

Avoid to call virtual method in destructor: using a callable as callback

I'm trying to remove a virtual method called in a destructor. In order to fix the code I'm trying to replace the virtual method using a std::function passed via constructor. Here a proof-of-concept where the stop method was virtual:

#include <functional>
#include <iostream>

class Base {
public:
    Base(const std::function<void(void)> &ff) :
            cc(ff) {
    }

    Base(std::function<void(void)> &&ff) :
            cc(std::move(ff)) {
    }

    virtual ~Base() {
        exitBase();
    }

    void exitBase() {
        cc();
    }
   
private:
    std::function<void(void)> cc;
};

class Child: public Base {
public:
    Child() :
            Base(std::bind(&Child::stop, this)) {
    }

    void stop() {
        std::cout << "bbb" << std::endl;
    }
protected:
    Child(const std::function<void(void)> &ff) :
            Base(ff) {
    }
    Child(std::function<void(void)> &&ff) :
            Base(std::move(ff)) {
    }
};

class Child2: public Child {
public:
    Child2() :
            Child([&]() {
                stop();
                Child::stop();
            }) {
    }

    using Child::stop;

    void stop() {
        std::cout << "ccc" << std::endl;
    }
private:
};

int main() {
    Child2 c;
    return 0;
}

I have two questions:

  1. Is there any lifetime violation? I think even if the lambda is capturing by reference and the parent destructor is calling a piece of code in the child, the object should be alive until parent destructor finish, is it right?
  2. If you see Child2 the lambda calls explicitly the stop in Child in addition to the stop defined in Child2. Is there any way to combine the calls at parent level instead of letting the child the responsibility to call the parent stop method?

Aucun commentaire:

Enregistrer un commentaire