gpt4 book ai didi

c++ - 释放在不同同步上下文中使用的类成员

转载 作者:行者123 更新时间:2023-11-28 04:59:07 25 4
gpt4 key购买 nike

我正在学习专业 C++ 第二版第 29 章的单例设计模式1。它说明了涵盖线程安全要求的 Logger 类的单例实现:

标题

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <mutex>
// Definition of a multithread safe singleton logger class
class Logger
{
public:
static const std::string kLogLevelDebug;
static const std::string kLogLevelInfo;
static const std::string kLogLevelError;
// Returns a reference to the singleton Logger object
static Logger& instance();
// Logs a single message at the given log level
void log(const std::string& inMessage,
const std::string& inLogLevel);
// Logs a vector of messages at the given log level
void log(const std::vector<std::string>& inMessages,
const std::string& inLogLevel);
protected:
// Static variable for the one-and-only instance
static Logger* pInstance;
// Constant for the filename
static const char* const kLogFileName;
// Data member for the output stream
std::ofstream mOutputStream;
// Embedded class to make sure the single Logger
// instance gets deleted on program shutdown.
friend class Cleanup;
class Cleanup
{
public:
~Cleanup();
};
// Logs message. The thread should own a lock on sMutex
// before calling this function.
void logHelper(const std::string& inMessage,
const std::string& inLogLevel);
private:
Logger();
virtual ~Logger();
Logger(const Logger&);
Logger& operator=(const Logger&);
static std::mutex sMutex;
};

实现

#include <stdexcept>
#include "Logger.h"
using namespace std;

const string Logger::kLogLevelDebug = "DEBUG";
const string Logger::kLogLevelInfo = "INFO";
const string Logger::kLogLevelError = "ERROR";
const char* const Logger::kLogFileName = "log.out";
Logger* Logger::pInstance = nullptr;
mutex Logger::sMutex;

Logger& Logger::instance()
{
static Cleanup cleanup;
lock_guard<mutex> guard(sMutex);
if (pInstance == nullptr)
pInstance = new Logger();
return *pInstance;
}
Logger::Cleanup::~Cleanup()
{
lock_guard<mutex> guard(Logger::sMutex);
delete Logger::pInstance;
Logger::pInstance = nullptr;
}
Logger::~Logger()
{
mOutputStream.close();
}
Logger::Logger()
{
mOutputStream.open(kLogFileName, ios_base::app);
if (!mOutputStream.good()) {
throw runtime_error("Unable to initialize the Logger!");
}
}
void Logger::log(const string& inMessage, const string& inLogLevel)
{
lock_guard<mutex> guard(sMutex);
logHelper(inMessage, inLogLevel);
}
void Logger::log(const vector<string>& inMessages, const string& inLogLevel)
{
lock_guard<mutex> guard(sMutex);
for (size_t i = 0; i < inMessages.size(); i++) {
logHelper(inMessages[i], inLogLevel);
}
}
void Logger::logHelper(const std::string& inMessage,
const std::string& inLogLevel)
{
mOutputStream << inLogLevel << ": " << inMessage << endl;
}

接着解释了为什么要引入友元类Cleanup:

The Cleanup class is there to make sure the single Logger instance gets deleted properly on program shutdown. This is necessary because this implementation is dynamically allocating the Logger instance by using the new operator in a block of code protected with a mutex. A static instance of the Cleanup class will be created the first time the instance() method is called. When the program terminates, the C++ runtime will destroy this static Cleanup instance, which will trigger the deletion of the Logger object and a call to the Logger destructor to close the file.

我觉得很困惑,它说“这是必要的,因为......”,好像别无选择。

我的问题:

1) 真的有必要吗?在析构函数中进行所有处理还不够吗?例如:

Logger::~Logger()
{
{
lock_guard<mutex> guard(Logger::sMutex);
delete Logger::pInstance;
Logger::pInstance = nullptr;
}
mOutputStream.close();
}

2)如果1)的答案是“是的,确实有必要!”,我想知道为什么。

1Professional C++,第二版,作者:Marc Gregoire、Nicholas A. Solter、Scott J. Kleper 出版商:Wrox 出版时间:2011 年 10 月

最佳答案

是的,在这种情况下需要这样做。由于本书使用了 new 并分发了一个指针,所以没有对象会超出范围导致析构函数触发。这样做的唯一方法是在该指针的某处调用 deleteCleanup 类不是要求您这样做。

如果您使用 Meyers Singleton,所有这些都可以避免。它使用单例类型的静态变量并返回指向它的指针/引用。与书本版本不同,它会在程序结束时自动销毁。 Meyers Singleton 看起来像:

class Singleton {
public:
static Singleton* Instance() { static Singleton s; return &s; }
Singleton(const Singleton&) = delete;
void operator=(const Singleton&) = delete;
private:
Singleton() = default;
};

关于c++ - 释放在不同同步上下文中使用的类成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46488136/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com