JuniorCodeVery commonNot answered yet
Implement the Singleton pattern (thread-safe, Meyer's).
Implement a thread-safe Singleton (Meyer's style) for a Logger class with a log(const std::string&) method.
Constraints:
- Exactly one instance per process;
instance()returns a reference (not a pointer). - Initialisation must be thread-safe with no manual mutex or
new. - It must be impossible to accidentally create a second instance.
class Logger {
public:
static Logger& instance();
void log(const std::string& msg);
// your code here
private:
Logger() = default;
~Logger() = default;
};
Write the implementation.
Meyer's Singleton uses a function-local static variable: C++11 guarantees magic statics are initialised exactly once in a thread-safe manner. Delete copy/move constructors and assignment to prevent extra instances.
- ✗Returning a pointer instead of a reference from
instance()— callers can accidentally delete the pointer or store nullptr; return a reference - ✗Implementing Singleton by storing a static pointer and calling
new— this is the pre-C++11 approach; it requires a mutex and is less clean than Meyer's static - ✗Not deleting copy/move operators — without
= delete, a caller can accidentally copy the singleton into a local variable, creating a second instance
- →How do you reset a Singleton in unit tests without exposing a public
reset()method? - →What is the 'dead reference problem' with Singleton and how does the Phoenix Singleton solve it?
Contents
Singleton Implementation (Meyer's, C++11)
class Logger {
public:
static Logger& instance() {
static Logger inst; // initialised exactly once, thread-safe (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;
};
Usage
int main() {
Logger::instance().log("Application started");
Logger& a = Logger::instance();
Logger& b = Logger::instance();
assert(&a == &b); // same object
}
Testable alternative: dependency injection
class ILogger {
public:
virtual void log(const std::string& msg) = 0;
virtual ~ILogger() = default;
};
class Service {
public:
explicit Service(ILogger& logger) : logger_(logger) {}
void doWork() { logger_.log("Working"); }
private:
ILogger& logger_;
};Contents