cpp中的构造函数无限循环

Constructors infinite cycle in cpp

我有一个 Logger 单例 class 其目的是将消息打印到日志文件/屏幕。 这个 Logger 有一些他想从配置文件中读取的配置。这是 Logger 的构造函数:

Logger::Logger(const std::string& confFilePath) {
    m_logConf = new LogConfig(confFilePath);
    ...
}

Class LogConfig 使用知道如何解析配置文件的配置对象。这里是 class Ctor:

LogConfig::LogConfig(const std::string& confFilePath) {
    m_config = new Configuration(confFilePath);
    ...
    m_config->ParseConfFile();
}

问题是在 ParseConfFile 方法中 - 配置对象可能想要写入日志并使用 Logger 单例 class。但是,当它尝试这样做时 - 他将再次进入 Logger 构造函数,然后进入 LogConfig Ctor 并且存在无限循环。

我不想禁止配置 class 写入日志(LogConfig 不是唯一使用它的 class)。

如何解决这个循环问题?

用最低限度初始化记录器,这样您根本不需要配置。 然后当你有配置时替换记录器。

如果配置 reader 需要记录任何内容,它将转到最低限度的记录器,因此您至少应该将其转储到 stderr。

此外,如果您在 multi-threaded 环境中,请确保您使用 shared_ptr 并进行原子交换以将其替换为合适的(以防其他模块在您需要时记录日志)交换)。

由于Logger是一个单例,假设所有类(包括Configuration)都通过静态方法(比如getInctance())访问它,而Logger 的构造函数是私有的。正确的方法是将 Logger 的构造简化到最低限度,并将 setup/configuration 逻辑从构造函数移至 getInstance().

类似于:

static Logger* Logger::getInstance() {
    if (m_logger == nullptr) {
        m_logger = new Logger();  // remove configuration path passing from the constructor
        m_logger->setConfigPath(const std::string& confFilePath); // ok trying to write to Logger, at least from the perspective of not being stuck in construction loop
    }
    return m_logger;
}

虽然这种情况下的行为仍然需要定义,因为当配置尝试写入时记录器没有完全初始化。

一种方法是在完全初始化之前有人想使用 Logger 时抛出异常或将错误消息写入标准输出。