Search code examples
c++c++11polymorphismcrtppure-virtual

CRTP causing segfault


I have a pure virtual class Interface:

class Interface {
  public:
    virtual ~Interface() noexcept;
    virtual void open()=0;
    virtual void close()=0;
  protected:
    explicit Interface(const string params);
    string params_;
}

I then have an abstract class where I implement my business logic:

template<typename T>
class AbstractInterface : public Interface {
  public:
    void open() override;
    void close() override;
    void read_is_complete(const vector<byte_array>);
  protected:
    explicit AbstractInterface(const string params);
    virtual ~AbstractInterface() noexcept;
}

Then there is the implementation for the interface that uses CRTP for polymorphism:

class SPInterface : public AbstractInterface<SPInterface> {
  public:
    explicit SPInterface(const string params);
    virtual ~SPInterface() noexcept;
    void open();
    void close();
    void read_is_complete(const vector<byte_array> data);
}

I have a unit test where I create an instance of SPInterface:

unique_ptr<Interface> intf;
intf.reset(new SPInterface("aaa"));

Letting this get out of scope calls the destructor AbstractInterface which in turn calls the close method on AbstractInterface and then it segfaults on this:

template<typename T>
void AbstractInterface<T>::close() {
  static_cast<T *>(this)->close();
  params_ = "";
}

Which is confusing as I already created an instance of the class. lldb seems to confirm:

AbstractInterface<SPInterface>::close(this=<unavailable>)

Solution

  • Letting this get out of scope calls the destructor AbstractInterface which in turn calls the close method on AbstractInterface and then it segfaults on this:

    template<typename T>
    void AbstractInterface<T>::close() {
        static_cast<T *>(this)->close();
        params_ = "";
    }
    

    It seems that you are trying to invoke a method of a derived class from within the destructor of a base class.
    This is not safe at all and a segfault is the way the executable has to tell you that it doesn't approve that. :-)

    Even though CRTP allows you to invoke a member function that belongs to the derived class on a (let me say) living object, it doesn't change the way an object is destructed.
    Do not forget that bases and members are destroyed in the reverse order of the completion of their constructor.