CRTP вызывает дочернюю функцию в деструкторе родителя

У меня есть два класса, структурированные так (упрощенный код, чтобы показать проблему более четко):

template<typename stream_type>
class Stream : public std::basic_streambuf<char, std::char_traits<char>>
{
private:
    std::string pBuffer;

    //other functions overridden here..

public:
    Stream();
    virtual ~Stream();

    Stream(const Stream& other) = delete;
    Stream& operator = (const Stream& other) = delete;
};

template<typename stream_type>
Stream<stream_type>::Stream() : pBuffer()
{
    parent_type::setg(nullptr, nullptr, nullptr);
    parent_type::setp(nullptr, nullptr);
}

template<typename stream_type>
Stream<stream_type>::~Stream()
{
    //Parent Destructor calling child member function..
    static_cast<stream_type*>(this)->sync(&pBuffer[0], pBuffer.size());
}


//CRTP Child..
template<typename char_type>
class File : public Stream<File<char_type>>
{
private:
    FILE* hStream;

public:
    File(const char* path) : Stream<File<char_type>>()
    {
        hStream = fopen(path, "w");
    }
    ~File()
    {
        //Child destructor is closing the file..
        fclose(hStream);
    }

    int sync(const char_type* data, std::size_t size)
    {
        if (fwrite(data, sizeof(char_type), size, hStream) == size)
        {
            fflush(hStream);
        }

        return traits_type::eof();
    }
};

Проблема:

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

Любые идеи о том, как я могу исправить такую ​​​​ситуацию? Мне нужно, чтобы родительский класс гарантировал, что все данные в его буфере синхронизируются с диском. Однако мой дочерний класс НЕ всегда может быть «файловым» классом. Это может быть другой тип потока, который не синхронизируется. Мне нужен родительский класс, чтобы заставить всех детей синхронизировать свои данные.

Любые идеи, как я могу это сделать?


person Brandon    schedule 09.06.2019    source источник
comment
Кажется, вам просто нужно поменять местами родительский и дочерний классы. А точнее ввести какой-то базовый базовый класс, который бы отвечал за синхронизацию   -  person user7860670    schedule 09.06.2019
comment
Однако мой дочерний класс НЕ всегда может быть классом File. Это может быть другой тип потока, который не синхронизируется. Мне нужен родительский класс, чтобы заставить всех детей синхронизировать свои данные. Разве это не противоречит самому себе? Тем не менее, кажется, что синхронизация является частью File отсутствия потоковой передачи, если некоторые дети не синхронизируются. Почему синхронизация в ~File нежелательна?   -  person Quimby    schedule 09.06.2019
comment
Вам нужно, чтобы File производилось косвенно от std::basic_streambuf<char, std::char_traits<char>>? Вам также нужно, чтобы Stream производился от этого класса? Могут быть некоторые альтернативы, если вы можете изменить иерархию классов или использовать включение вместо или в дополнение к наследованию.   -  person Phil1970    schedule 16.06.2019


Ответы (1)


Элементы и базы уничтожаются в порядке, обратном их созданию.
Таким образом, одним из решений может быть создание класса-оболочки около FILE*, и иметь
его в качестве более ранней базы, чем Stream, чтобы он уничтожался позже;

template<typename char_type>
class File : private CFileWrapper, public Stream<File<char_type>>
person sp2danny    schedule 11.06.2019