以下代码是否安全地使用自定义消息抛出异常?
#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
的消息“给我5”仍然可以在catch-block中找到?在打印消息时,应该删除流和临时字符串对象吗?顺便说一句:这种为异常生成消息的方式似乎也适用于多个函数,如果在打印异常之前在catch块中分配了新内存。
或者是否有必要使用std :: string成员定义自定义异常类,以便安全地保留消息直到打印它。
答案 0 :(得分:5)
这是非常安全的。将C字符串作为单个参数的构造函数构成字符串的副本。采用C字符串和长度参数的构造函数允许您指定不分配内存并存储指向字符串的指针(忽略length参数)。
请注意,这两个构造函数是std::exception
类的扩展,不是标准的。另请注意,将C字符串作为单个参数的构造函数未标记为显式。
答案 1 :(得分:4)
按照§15.1/ 3:
抛出异常copy-initializes(8.5,12.8)一个临时对象, 称为异常对象。
和§15.1/ 4:
异常对象的内存以未指定的方式分配 方式,除了3.7.4.1中所述。如果处理程序通过重新抛出退出, 控件被传递给另一个处理程序以获得相同的异常。该 异常对象在最后一个活动后被销毁 异常处理程序通过除了重新抛出之外的任何方式退出......
所以在throw expression
之后:
表达式将被复制(新对象将由复制构造函数创建),您不必担心本地对象。
关于你担心的msg
和const 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
而不仅仅是存储指针。
答案 2 :(得分:3)
不,它不安全,因为std::exception
没有构造函数在标准中使用char *。您正在使用MS扩展程序。为了使其便于携带和安全,请改用std::runtime_error
,您可以在其中传递std::string
。