首页 > 解决方案 > 在 std::exception.what() 中使用 std::stringstream

问题描述

想要实现std::exception 类,尤其是what 函数,我遇到了std::stringstream 的问题。

简而言之,当我使用此实现时,它会打印一个空字符串:

const char *what() const throw () {
   std::stringstream ss;

   ss << "Error";
   if (_line > -1)
      ss << " at line " << std::to_string(_line);

   ss << ": " << _msg;

   return ss.str().c_str();
}

并在我使用此实现时打印一些东西(例如:“第 3 行错误”):

const char *what() const throw () {
   std::stringstream ss;

   ss << "Error";
   if (_line > -1)
      ss << " at line " << std::to_string(_line);

   //ss << ": " << _msg; // COMMENT THIS LINE

   return ss.str().c_str();
}

然后我什至尝试查看它是来自“:”还是来自变量 _msg (std::string) 但它们似乎都没有影响。

这是字符串流方面的缓冲区问题还是我方面的操作问题?如果这是一个操作问题,请解释我如何使用它。

标签: c++exceptionbufferstringstream

解决方案


ss.str().c_str();

str()做这个:

返回底层字符串的副本 [..]

(资源)

所以你现在有一个临时std::string的,你打电话c_str()。这将返回一个指向由该临时管理std::string的 (C) 字符串的指针。

因此,一旦此语句结束(在这种情况下,当函数返回时)临时std::string将被破坏,这将删除/释放您从c_str()指向的指针指向的内存。

所以你有一个无效的指针,访问它是未定义的行为。

解决方案:

  1. 制作 C 字符串的副本,然后将其返回。 不好,因为现在调用者必须释放这个副本,而这不是“API”的一部分std::exception::what()

  2. 向您的类添加一个std::string成员,用(最好在类的构造函数中)的返回值填充它并返回该成员的内部 C 字符串:str()

    struct my_exception : public std::exception {
      std::string description;
      my_exception() {
        std::stringstream ss;
        // code to fill ss
        description = ss.str();
      }
      char const * what() const override {
        return description.c_str();
      }
    };
    

保留核桃的重要评论:

不过,您需要小心。std::string复制时可能会抛出,如果发生这种情况,例如通过复制捕获的异常处理程序,std::terminate将被调用并且程序将中止。另一方面,它可能只会在内存分配失败时抛出,这可能是一个您认为无论如何都无法恢复的错误(或不是)。


推荐阅读