I got a class which holds the application's logger as a unique_ptr. The logger can be set through a static function. Also, one can obviously log messages. I left out any thread synchronization (mutexes) to make things easier.
class LoggerWrapper {
public:
static void SetLogger(std::unique_ptr<logger::ILogger> new_logger);
static void Log(const std::string& message);
private:
static std::unique_ptr<logger::ILogger> logger_;
};
void LoggerWrapper::Log(const std::string& message) {
if (!logger_) {
// cannot log
} else {
logger_->OnLogEvent(message);
}
}
void LoggerWrapper::SetLogger(std::unique_ptr<logger::ILogger> new_logger) {
logger_ = std::move(new_logger);
}
My problem is: The unique_ptr gets destructed before some of the other classes inside the application. E.g. is the DTOR of Class Foo
wants to log something, the unique_ptr might have already been destroyed (which is the case at the moment). This causes the ILogger
implementation to be destroyed, resulting in no log output being possible.
Does anyone have an idea on how to easily fix this? I somehow need to "delay" the destruction of the static unique_ptr. I also tried changing it to a shared_ptr, but that only caused SIGABRTs with "pure virtual method called" errors.
Thanks in advance!
EDIT: Created a minimal working example which contradicts my experience. In this case, the static logger outlives the Foo
class.
EDIT2: My application uses exit
. That seems to change the order of destruction.
EDIT3: exit
does not destroy local objects.
/******************************************************************************
Online C++ Compiler.
Code, Compile, Run and Debug C++ program online.
Write your code in this editor and press "Run" button to compile and execute it.
*******************************************************************************/
#include <iostream>
#include <memory>
#include <string>
using namespace std;
class ILogger {
public:
ILogger() {
std::cout << "ILogger CTOR" << std::endl;
}
~ILogger() {
std::cout << "ILogger DTOR" << std::endl;
}
virtual void OnLogEvent(const std::string& log_message) {
std::cout << "OnLogEvent: " << log_message << std::endl;
}
};
class LoggerWrapper {
public:
static void SetLogger(std::unique_ptr<ILogger> new_logger) {
logger_ = std::move(new_logger);
}
static void Log(const std::string& message) {
if (!logger_) {
// cannot log
} else {
logger_->OnLogEvent(message);
}
};
private:
static std::unique_ptr<ILogger> logger_;
};
class Foo {
public:
Foo(const std::string& name) : name_{name} {
LoggerWrapper::Log(name_ + ": CTOR");
}
~Foo() {
LoggerWrapper::Log(name_ + ": DTOR");
}
private:
std::string name_;
};
// declaring logger_ first causes it to be deleted AFTER foo
std::unique_ptr<ILogger> LoggerWrapper::logger_;
std::unique_ptr<Foo> foo;
int main()
{
LoggerWrapper::SetLogger(std::make_unique<ILogger>());
foo = std::make_unique<Foo>("Global FOO");
// local variables do NOT get destroyed when calling exit!
auto foo_local = Foo("Local FOO");
exit(1);
}