带有unique_ptr的CRTP导致段错误

时间:2018-08-27 22:49:19

标签: c++ c++14 crtp

我正在使用CRTP设计模式为我的项目实现日志记录机制。基本的CRTP类如下:

input[type=checkbox] {
display:none;
}
 
input[type=checkbox] + label
{
background: #999;
height: 16px;
width: 16px;
display:inline-block;
padding: 0 0 0 0px;
}
input[type=checkbox]:checked + label
{
background: #0080FF;
height: 16px;
width: 16px;
display:inline-block;
padding: 0 0 0 0px;
}

具体的日志记录类之一是记录到文件,如下所示:

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
   <p>
    <input class="select-one checkbox-default-input" type="checkbox" :value="placement.id" v-model="checkedPlacements" id="select-clicks1">
    <label for="select-clicks1" class="checkbox-default"></label>
    <input class="select-one checkbox-default-input" type="checkbox" :value="'value2'" v-model="checkedPlacements" id="select-clicks2">
    <label for="select-clicks2" class="checkbox-default"></label>
   </p>
   <p>
    <input class="select-one checkbox-default-input" type="checkbox" :value="placement.id" v-model="checkedPlacement" id="select-clicks3">
    <label for="select-clicks3" class="checkbox-default"></label>
   </p>
</div>

基本上,我创建策略类的对象,并希望根据所选择的策略记录内容。例如,我创建这样的记录器:

#include <fstream>
#include <memory>
#include <mutex>
#include <iostream>
#include <sstream>

template <typename LogPolicy>
class Logger
{
  public:
    template <typename... Args>
    void operator()(Args... args)
    {
        loggingMutex.lock();
        putTime();
        print_impl(args...);
    }

    void setMaxLogFileSize(unsigned long maxLogFileSizeArg)
    {
        //if (dynamic_cast<FileLogPolicy *>(policy.get()))
        //    policy->setMaxLogFileSize(maxLogFileSizeArg);
    }

    ~Logger()
    {
        print_impl(END_OF_LOGGING);
    }

  protected:
    std::stringstream buffer;
    std::mutex loggingMutex;
    std::string d_time;
  private:
    static constexpr auto END_OF_LOGGING = "***END OF LOGGING***";

    void putTime()
    {
        time_t raw_time;
        time(&raw_time);
        std::string localTime = ctime(&raw_time);
        localTime.erase(std::remove(localTime.begin(), localTime.end(), '\n'), localTime.end());
        buffer << localTime;
    }

    template <typename First, typename... Rest>
    void print_impl(First first, Rest... rest)
    {
        buffer << " " << first;
        print_impl(rest...);
    }

    void print_impl()
    {
        static_cast<LogPolicy*>(this)->write(buffer.str());
        buffer.str("");
    }
};

在这种情况下,应使用Logger通过调用#include "Logger.hpp" class FileLogPolicy : public Logger<FileLogPolicy> { public: FileLogPolicy(std::string fileName) : logFile(new std::ofstream) { logFile->open(fileName, std::ofstream::out | std::ofstream::binary); if (logFile->is_open()) { std::cout << "Opening stream with addr " << (logFile.get()) << std::endl; } } void write(const std::string content) { std::cout << "Writing stream with addr " << (logFile.get()) << std::endl; (*logFile) << " " << content << std::endl; loggingMutex.unlock(); } virtual ~FileLogPolicy() { } private: std::unique_ptr<std::ofstream> logFile; //Pointer to logging stream static const char *const S_FILE_NAME; //File name used to store logging size_t d_maxLogFileSize; //File max size used to store logging }; 将日志保存到文件中。显然,调用write函数可以正常工作,但流对象更改为null。如果尚未调用FileLogPolicy析构函数,那怎么可能?当我将logFile更改为普通指针时,一切正常。我不明白区别在哪里。

1 个答案:

答案 0 :(得分:2)

~Logger()
{
    print_impl(END_OF_LOGGING);
}

此代码在后代类被破坏后运行。

void print_impl()
{
    static_cast<LogPolicy*>(this)->write(buffer.str());
    buffer.str("");
}

然后将this强制转换为指向不再this的类的指针。

唯一的ptr不见了,甚至访问该成员也是UB。