从std :: exception的`what`返回一个动态字符串

时间:2010-04-10 16:43:40

标签: c++ exception const

此时我确信我应该为所有异常抛出需求创建std::exception的子类。现在我正在研究如何覆盖what方法。

我所面临的情况,如果字符串what返回是动态的,那将非常方便。例如,某些代码解析XML文件,并在错误消息中添加位置或行号对我很有用。

我正在尝试关注Boost Exception handling guidelines

我想知道的事情:

  • what返回const char *,这意味着任何捕手都可能不会释放该字符串。所以我需要一些其他的地方来存储结果,但那会是哪里? (我需要线程安全。)

  • what在其签名中还包含throw()。虽然我可以阻止我的what投掷任何东西,但在我看来,这种方法实际上不适用于任何过于动态的东西。如果what不是正确的地方,那么我应该在哪里做这个呢?


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

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

还有其他选择吗?

4 个答案:

答案 0 :(得分:16)

我的异常类通常除了构造函数之外没有任何东西,并且看起来是这样的:

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的指导方针,也许您应该注意数字数据(位置和线)最好通过其他方法作为数字提供的点。指南说,不要担心what()消息。

答案 1 :(得分:6)

Boost的指南似乎基于两个假设:复制异常对象可能会引发另一个异常,而what()字符串不是一个强大或可靠的工具。如果您正在编写一个可以在各种环境中广泛使用的库,这些都是有效的问题。如果您更好地了解如何使用该例外,您可以判断这些问题是否合理或者无关紧要。编程是关于一系列的权衡,对Boost开发人员有意义的权衡可能不适用于你。

答案 2 :(得分:3)

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

答案 3 :(得分:1)

我接受了UncleBens的回答,因为我认为它在技术上是对我原始问题的最正确和最完整的答案。

作为参考,我实际上选择了一个不同的解决方案,并完全停止使用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;
};

基本上只是填充what我能找到的最有意义的东西,而不用在其他任何地方打扰它。我猜我会看到这种票价。