8

以下代码是否安全地使用自定义消息引发异常?

#include <exception>
#include <sstream>
#include <string>
#include <iostream>

int main() {
  try {
    std::ostringstream msg;
    msg << "give me " << 5;
    throw std::exception(msg.str().c_str());
  } catch (std::exception& e) {
    std::cout << "exception: " << e.what();
  }
}

使用 VC++-2008,这给出了:

exception: give me 5

但是现在我想知道为什么来自本地对象的消息“给我 5”msg仍然在 catch-block 中可用?在打印消息时,流对象和临时字符串对象都应该被删除吗?顺便说一句:这种为异常生成消息的方式似乎也适用于多个函数,并且如果在打印异常之前在 catch 块中分配了新内存。

或者是否有必要使用 std::string 成员定义自定义异常类,以便安全地保留消息直到打印它。

4

3 回答 3

6

这是完全安全的。将 C 字符串作为单个参数的构造函数会复制该字符串。采用 C 字符串和长度参数的构造函数允许您指定不分配内存并存储指向字符串的指针(忽略长度参数)。

请注意,这两个构造函数是std::exception类的扩展,不是标准的。另请注意,将 C 字符串作为单个参数的构造函数未标记为显式。

于 2013-05-21T19:44:37.030 回答
4

没关系。

根据§15.1/3:

抛出异常复制初始化(8.5、12.8)一个临时对象,称为异常对象。

和§15.1/4:

异常对象的内存以未指定的方式分配,除非在 3.7.4.1 中注明。如果一个处理程序通过重新抛出而退出,则控制权将传递给另一个处理程序以处理相同的异常。在异常的最后一个剩余活动处理程序以除重新抛出之外的任何方式退出后,异常对象被销毁......

所以之后throw expression

表达式将被复制(新对象将由复制构造函数创建),您不必担心本地对象。

 

关于msgconst char*你担心的......这是微软的实现:

exception::exception(const char * const & _What)
: _Mywhat(NULL), _Mydofree(false)
{
   _Copy_str(_What);
 //^^^^^^^^^^^^^^^^^
}

void exception::_Copy_str(const char * _What)
{
   if (_What != NULL)
   {
      const size_t _Buf_size = strlen(_What) + 1;
      _Mywhat = static_cast<char *>(malloc(_Buf_size));
       if (_Mywhat != NULL)
       {
         _CRT_SECURE_STRCPY(const_cast<char *>(_Mywhat), _Buf_size, _What);
       //^^^^^^^^^^^^^^^^^^
         _Mydofree = true;
       }
   }
 }

它复制的_What不仅仅是存储指针。

于 2013-05-21T19:54:24.910 回答
3

不,这不安全,因为std::exception在标准中没有采用 char* 的构造函数。您正在使用 MS 扩展。为了使其便携和安全,请改用它,您可以在 ctor 中将std::runtime_errora 传递给它。std::string

于 2013-05-21T19:30:51.903 回答