2016-12-01 9 views
1

У меня есть чисто виртуальный класс Interface:CRTP вызывает Segfault

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

Я тогда абстрактный класс, где я реализовать свой бизнес-логику:

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; 
} 

Тогда есть реализация для интерфейса, использует CRTP для полиморфизма:

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); 
} 

У меня есть единичный тест, где я создаю insta сть из SPInterface:

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

Позволить это выйти за рамки вызывает деструктор AbstractInterface, который в свою очередь, вызывает близкий метод на AbstractInterface и затем возвращает ошибку сегментации на this:

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

Что сбивает с толку, как я уже создал экземпляр класса. lldb, кажется, подтверждает:

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

Можно ли попытаться вызвать метод производного класса из деструктора базового класса? – skypjack

+1

Думаю, у вас там есть точка :) – ruipacheco

ответ

3

Позволить это выйти за рамки вызывает деструктор AbstractInterface, который в свою очередь, вызывает близкий метод на AbstractInterface, а затем он возвращает ошибку сегментации на этом:

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

Кажется, что вы пытаетесь вызвать метод производного класса из деструктора базового класса.
Это небезопасно, и segfault - это то, как исполняемый должен сказать вам, что он этого не одобряет. :-)

Несмотря на то, что CRTP позволяет вызывать функцию-член, принадлежащую производному классу на (я говорю) живом объекте, он не изменяет способ разрушения объекта.
Не забывайте, что основания и элементы уничтожены в порядке, обратном порядку завершения их конструктора.