【问题标题】:How can I call what() after throwing an unhandled, custom exception?抛出未处理的自定义异常后如何调用 what()?
【发布时间】:2017-02-27 18:27:46
【问题描述】:

当您抛出并未处理std::runtime_error 时,终端会自动打印what() 的结果,从而使调试更加容易。示例:

#include <iostream>

int main()
{
    throw std::runtime_error("This is an error message.\n");
}

控制台输出:

terminate called after throwing an instance of 'std::runtime_error'
what():  This is an error message.

由此类派生的自定义异常类显示相同的行为,从头开始创建的异常类默认情况下不会这样做。

但是我想创建的异常类不能从std::runtime_error派生。出于调试目的,what() 仍应在程序崩溃后打印-但我不知道该怎么做有什么关系!有人可以帮帮我吗?

目前看起来是这样的:

#include <iostream>

struct Custom_Exception
{
    std::string Msg;

    Custom_Exception(std::string Error_Msg) noexcept
    {
        Msg=Error_Msg;
    }

    std::string what() noexcept
    {
        return Msg;
    }
};

int main()
{
    throw Custom_Exception("This is an error message.\n");
}

控制台输出:

terminate called after throwing an instance of 'Custom_Exception'

错误消息中没有what():...将std::cout&lt;&lt;Msg; 放入析构函数也无济于事。

请帮助我提出您的建议!谢谢。

【问题讨论】:

  • "但是我要创建的异常类不能从std::runtime_error派生。" - 为什么不呢?
  • 在 main 中捕获你的异常,然后用它们做你想做的事。我不会依赖运行时为您执行此操作。
  • @NeilButterworth 它迫使我使用某些数据类型或每次都转换它们,它阻止我创建一个我想用于我自己的项目的通用异常类,我想知道如何出于好奇添加此功能。我只是不喜欢那样。否则我可以只使用 std::runtime_error 本身...但是我想要自定义异常类,因为它可以执行某些 std::runtime_error 不能做的事情。
  • @Thynome “但是我想要自定义异常类,因为它可以完成某些 std::runtime_error 不能做的事情。” 请您详细说明一下吗?
  • 我不推荐通用异常类。

标签: c++ debugging exception custom-exceptions


【解决方案1】:

what()std::terminate_handler 一起使用的最小异常接口是std::exception

struct Custom_Exception : public std::exception {
    std::string Msg;
public:
    Custom_Exception(std::string Error_Msg) noexcept : Msg(Error_Msg) {
    }

    const char* what() const { return Msg.c_str(); }
};

另一个不从std::exception 接口继承的选项是在main() 中捕获您的自定义异常

int main()
{
    try {
        throw Custom_Exception("This is an error message.\n");
    }
    catch(const Custom_Exception& ce) {
        std::cerr << ce.what() << std::endl;
    }
}

或使用您自己的处理程序覆盖并设置std::terminate_handler

【讨论】:

  • 您能解释一下如何正确覆盖std::terminate_handler 以及如何将它集成到我的异常类中吗?
  • @Thynome 我最终不确定std::terminate_handler 覆盖函数是否可以像try { throw; } catch(const Custom_Exception&amp; ce) { /* ... */ } 一样重新抛出和捕获。
  • 你可以。 [except.handle]/7 表示由于抛出而进入 std::terminate()[...] 时,隐式处理程序被认为是活动的,因此您可以安全地从那里重新抛出异常。
【解决方案2】:

您应该从提供虚拟析构函数和虚拟 what() 方法的 std::exception 派生您的异常。如果您覆盖析构函数,您应该能够打印您的消息。

#include <iostream>
#include <exception>

class Custom_Exception : std::exception
{
    char const* Msg;

    Custom_Exception(char const* Error_Msg) noexcept
    {
        Msg=Error_Msg;
    }

    Custom_Exception(Custom_Exception const& other)
    {
        Msg = other.Msg;
    }

    Custom_Exception& operator=(Custom_Exception const& other)
    {
        Msg = other.Msg;
        return *this;
    }

    virtual ~Custom_Exception()
    {
    }

    virtual char const* what() const noexcept
    {
        return Msg;
    }
};

int main()
{
    try 
    {
      throw Custom_Exception("This is an error message.\n");
    }
    catch (Custom_Exception& ex)
    {
      std::cout << "what(): " << ex.what();
    }
}

【讨论】:

  • 即使从未抛出异常,这不会打印错误消息吗?就算被抓到了?
  • 哦,是的。每当异常被破坏时。所以 πάντα ῥεῖ 对外部捕获的回答可能有效。
  • 输出错误信息不是析构函数的责任。这就是 what() 存在的原因,以便在需要时返回错误消息。
猜你喜欢
  • 1970-01-01
  • 2016-04-18
  • 2017-11-30
  • 1970-01-01
  • 1970-01-01
  • 2011-10-10
  • 1970-01-01
  • 2013-06-08
  • 1970-01-01
相关资源
最近更新 更多