CRTP вызов дочерней функции в деструкторе родителя - PullRequest
3 голосов
/ 09 июня 2019

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

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

Проблема:

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

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

Есть идеи, как мне это сделать?

1 Ответ

1 голос
/ 11 июня 2019

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

template<typename char_type>
class File : private CFileWrapper, public Stream<File<char_type>>
...