【问题标题】:Generic logger vs. exception pattern通用记录器与异常模式
【发布时间】:2021-07-20 06:30:29
【问题描述】:

考虑一个类foo,它具有一个或多个函数,可以通过记录器或在未提供记录器时抛出异常来报告失败:

struct logger
{
    // ...
};

struct foo
{
    void set_logger(std::shared_ptr<logger> logger) { m_logger = std::move(logger); }

    bool bar(const std::filesystem::path& path)
    {
        // Check path validity
        if (not std::filesystem::exists(path) {
            if (m_logger) {
                m_logger->warn("path does not exist.");
                return false;
            }
            else {
                throw std::runtime_error("path does not exists.");
            }
        }

        // Some random operation
        try {
            // Do something here that might throw
        }
        catch (const std::exception& e) {
            if (m_logger) {
                m_logger->warn("operation bar failed.");
                return false;
            }
            else {
                throw e;
            }
        } 
        return true;
    }

private:
    std::shared_ptr<logger> m_logger;
};

这不仅看起来难看,而且极易出错,并且随着更多功能添加到foo 代码将是重复的。

是否有任何模式或范式可以将这种逻辑抽象出来?当需要错误报告时,我可以构造某种包装模板以在 foo 的各种函数中使用?

任何达到 C++20 的都可以接受。

【问题讨论】:

    标签: c++ exception logging


    【解决方案1】:

    是否有任何模式或范式可以将这种逻辑抽象出来?当需要错误报告时,我可以构建某种包装模板以在 foo 的各种函数中使用?

    您可以做的一件事是简单地删除所有else { throw... } 代码并提供一个默认记录器,该记录器会引发包含记录消息的异常。如果客户端提供不同的记录器,很好,您的代码将使用它;如果不是,则使用默认值。此方案消除了大约一半的错误处理代码并简化了流程,同时提供了相同的行为,这似乎是一个积极的结果。

    请务必记住,记录消息与引发异常不同:能够记录不停止程序流的消息通常很有用。所以一定要给你的记录器类方法,记录而不抛出;您可以对等同于异常的消息使用不同的日志级别。

    【讨论】:

      【解决方案2】:

      由于您的错误案例处理似乎遵循相同的结构,您可以添加一个简单的函数来做到这一点:

      bool log_or_throw(logger * logger_, std::string const& message, std::exception const& exception) {
          if (logger_) {
              logger_->warn(message);
              return false;
          }
          else {
              throw exception;
          }
      }
      

      然后您可以将错误处理更改为一行,这可能会使流程更具可读性:

      if (not std::filesystem::exists(path) {
          return log_or_throw(m_logger, "path does not exist.", std::runtime_error("path does not exists."));
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-17
        • 2010-10-31
        • 2012-10-28
        • 2014-03-31
        • 2020-12-22
        • 1970-01-01
        相关资源
        最近更新 更多