【发布时间】:2021-09-19 11:44:55
【问题描述】:
我有一个类,它将应用程序的记录器保存为 unique_ptr。记录器可以通过静态函数进行设置。此外,显然可以记录消息。我省略了任何线程同步(互斥体)以使事情变得更容易。
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);
}
我的问题是:unique_ptr 在应用程序中的其他一些类之前被破坏。 例如。是Class Foo 的 DTOR 想要记录一些东西,unique_ptr 可能已经被销毁(目前就是这种情况)。这会导致 ILogger 实现被破坏,导致无法输出日志。
有人知道如何轻松解决此问题吗?我需要以某种方式“延迟”静态 unique_ptr 的破坏。我也尝试将其更改为 shared_ptr,但这只会导致 SIGABRT 出现“调用纯虚拟方法”错误。
提前致谢!
编辑:创建了一个与我的经验相矛盾的最小工作示例。在这种情况下,静态记录器比 Foo 类寿命更长。
EDIT2:我的应用程序使用exit。这似乎改变了破坏的顺序。
EDIT3:exit 不会 破坏本地对象。
/******************************************************************************
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);
}
【问题讨论】:
-
静态对象的破坏顺序与构造顺序相反。使用静态存储时长来控制事物的构建顺序并不总是那么容易。如果可能的话,我会完全摆脱对订单的依赖。也许将日志从析构函数移动到
before_exit方法或其他东西。 -
@super 感谢您的回答。是的,我正在考虑改用
Shutdown方法。尽管如此,我还是很难找到另一个解决方案:D -
@super 我以前听说过逆向构造顺序。但这仅适用于静态变量,对吗?例如。静态变量
A是在静态变量B之前构造的,所以在它之后就被销毁了。是否有任何规则可以确定静态成员(例如我的记录器)是否在另一个使用它的非静态类(例如Foo)之前/之后被破坏? -
This 可能有点相关,虽然有点老了。
-
是的,具有非静态存储持续时间的东西总是会在任何静态对象被破坏之前超出范围。
标签: c++ pointers logging static destructor