我正在使用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更改为普通指针时,一切正常。我不明白区别在哪里。
答案 0 :(得分:2)
~Logger()
{
print_impl(END_OF_LOGGING);
}
此代码在后代类被破坏后运行。
void print_impl()
{
static_cast<LogPolicy*>(this)->write(buffer.str());
buffer.str("");
}
然后将this
强制转换为指向不再this
的类的指针。
唯一的ptr不见了,甚至访问该成员也是UB。