代码之家  ›  专栏  ›  技术社区  ›  Stéphan Kochen

返回STD::“异常”的动态字符串

  •  16
  • Stéphan Kochen  · 技术社区  · 15 年前

    在这一点上,我确信我应该创建 std::exception 为了我所有的例外扔需要。现在我正在研究如何覆盖 what 方法。

    我所面对的情况,如果绳子 什么 返回动态。例如,一些代码解析一个XML文件,在错误消息中添加一个位置或行号对我很有用。

    我正试图跟随 Boost Exception handling guidelines

    我想知道的是:

    • 什么 返回 const char * 这意味着任何收集器都不可能释放字符串。所以我需要其他地方来存储结果,但那会是什么地方呢?(我需要螺纹安全。)

    • 什么 还包括 throw() 在它的签名上。当我可以阻止 什么 从抛出任何东西开始,在我看来,这个方法实际上并不适用于太动态的东西。如果 什么 不是正确的地方,那么我应该在哪里做呢?


    从我到目前为止得到的答案来看,实现这一点的唯一方法似乎是将字符串存储在异常中。Boost指南建议不要这样做,这让我很困惑,因为 std::runtime_error 就是这样。

    即使我要使用C字符串,我也必须使用静态大小的缓冲区,或者进行内存管理,这也可能会失败。(我想知道这是否是唯一可能出错的 std::string 的复制构造函数。这意味着我不会使用动态分配的C字符串获得任何东西。)

    还有其他选择吗?

    4 回复  |  直到 15 年前
        1
  •  16
  •   UncleBens    15 年前

    我的异常类通常除了构造函数之外没有其他内容,并沿着这些行进行查看:

    class MyEx: public std::runtime_error 
    {
    public: 
        MyEx(const std::string& msg, int line): 
            std::runtime_error(msg + " on line " + boost::lexical_cast<string>(line)) 
        {} 
    }; 
    

    一个任意的示例,但它是处理管理 what() 消息。

    但是,如果您想这样做,也只能在将消息放在构造函数体中之后,分配异常对象的基本部分。

    #include <stdexcept>
    #include <string>
    #include <sstream>
    
    class MyEx: public std::runtime_error
    {
    public:
        MyEx(const std::string& msg, int line):
            std::runtime_error("")
        {
            std::stringstream ss;
            ss << msg << " on line " << line;
            static_cast<std::runtime_error&>(*this) = std::runtime_error(ss.str());
        }
    };
    
    #include <iostream>
    int main()
    {
        try {
            throw MyEx("Evil code", __LINE__);
        }
        catch (const std::exception& e) {
            std::cout << e.what() << '\n';
        }
    }
    

    然而,关于Boost的指导方针,也许您应该注意数字数据(位置和行)最好通过其他方法作为数字提供。指导方针说不要担心 什么() 消息。

        2
  •  6
  •   Mark Ransom    15 年前

    Boost的指导原则似乎基于两个假设:复制异常对象可能会引发另一个异常,而what()字符串不是一个健壮或可靠的工具。如果您正在编写一个可以在各种环境中广泛使用的库,那么这些问题是有效的。如果您对如何使用异常有更好的了解,那么您可以判断这些关注是否合理,或者是否无事生非。编程就是一系列的权衡,而那些对提振开发者有意义的权衡可能不适用于您。

        3
  •  3
  •   Hans Passant    15 年前

    好吧,没问题,您可以简单地实现派生异常类的构造函数来格式化将从what()返回的字符串。释放在析构函数中用于此目的的缓冲区。

        4
  •  1
  •   Stéphan Kochen    15 年前

    我接受叔叔的回答,因为从技术上讲,我认为这是对我原来问题最正确和最完整的回答。

    作为参考,我实际上选择了一个不同的解决方案,并停止使用 what 总共。我已经重构了代码,现在我要将类似这样的代码用作基本异常类:

    struct Exception : public virtual std::exception
    {
      virtual const char* what() const throw()
      {
        try {
          return typeid(this).name();
        }
        catch (const std::exception& e) {
          return "<unknown exception>";
        }
      }
    
      // Extended description; may throw.
      virtual void describe(std::ostream& out) const = 0;
    };
    

    基本上只是填充 什么 我能找到最有意义的东西,而不必在其他任何地方费心。我想我要看看这个价格如何。