JuniorКодОчень частоЕщё не отвечали
Реализуйте паттерн Singleton (потокобезопасный, по Майерсу).
Реализуйте потокобезопасный Singleton (по Майерсу) для класса Logger с методом log(const std::string&).
Ограничения:
- Ровно один экземпляр на процесс;
instance()возвращает ссылку (не указатель). - Инициализация должна быть потокобезопасной без ручного мьютекса и
new. - Создание второго экземпляра должно быть невозможным.
class Logger {
public:
static Logger& instance();
void log(const std::string& msg);
// ваш код здесь
private:
Logger() = default;
~Logger() = default;
};
Допишите реализацию.
Singleton Майерса использует локальную static-переменную: C++11 гарантирует, что magic statics инициализируются ровно один раз потокобезопасно. Удалите копирование/перемещение для запрета лишних экземпляров.
- ✗Возвращать указатель вместо ссылки из
instance()— вызывающие могут случайно удалить указатель или хранить nullptr; возвращайте ссылку - ✗Реализовывать Singleton хранением статического указателя и вызовом
new— это подход до C++11; он требует мьютекса и менее чист, чем static Майерса - ✗Не удалять операторы копирования/перемещения — без
= deleteвызывающий может случайно скопировать синглтон в локальную переменную, создав второй экземпляр
- →Как сбросить Singleton в юнит-тестах без открытого метода
reset()? - →Что такое 'проблема мёртвой ссылки' с Singleton и как её решает Phoenix Singleton?
Оглавление
Реализация Singleton (по Майерсу, C++11)
class Logger {
public:
static Logger& instance() {
static Logger inst; // инициализируется один раз, потокобезопасно (C++11)
return inst;
}
void log(const std::string& msg) {
std::cout << "[LOG] " << msg << '\n';
}
// Запрет копирования и перемещения
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
Logger(Logger&&) = delete;
Logger& operator=(Logger&&) = delete;
private:
Logger() = default;
~Logger() = default;
};
Использование
int main() {
Logger::instance().log("Application started");
Logger::instance().log("Step 2");
Logger& a = Logger::instance();
Logger& b = Logger::instance();
assert(&a == &b); // один и тот же объект
}
Альтернатива для тестирования: инъекция зависимостей
// Вместо Singleton — передавайте интерфейс явно
class ILogger {
public:
virtual void log(const std::string& msg) = 0;
virtual ~ILogger() = default;
};
class ConsoleLogger : public ILogger {
public:
void log(const std::string& msg) override {
std::cout << msg << '\n';
}
};
class Service {
public:
explicit Service(ILogger& logger) : logger_(logger) {}
void doWork() { logger_.log("Working"); }
private:
ILogger& logger_;
};
Оглавление