std::使用来自本地对象的消息时发生异常

std::exception using message from local object

本文关键字:消息 异常 对象 std      更新时间:2023-10-16

下面的代码是否安全地使用自定义消息抛出异常?

#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

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

或者有必要定义一个带有std::string成员的自定义异常类,以便在打印消息之前安全地保存消息

它非常安全。将C字符串作为单个参数的构造函数生成该字符串的副本。使用一个C字符串和一个长度参数的构造函数,可以指定不分配内存,并存储指向该字符串的指针(忽略长度参数(。

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

还好

根据§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,而不仅仅是存储指针。

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