C ++异常:抛出std :: string
时间:2020-03-06 14:44:02 来源:igfitidea点击:
当我的C ++方法遇到奇怪的东西并且无法恢复时,我想抛出一个异常。可以抛出一个std :: string指针吗?
这是我期待做的事情:
void Foo::Bar() {
if(!QueryPerformanceTimer(&m_baz)) {
throw new std::string("it's the end of the world!");
}
}
void Foo::Caller() {
try {
this->Bar(); // should throw
}
catch(std::string *caught) { // not quite sure the syntax is OK here...
std::cout << "Got " << caught << std::endl;
}
}
解决方案
它有效,但是如果我是你,我不会这样做。完成后,我们似乎并没有删除该堆数据,这意味着我们已经创建了内存泄漏。 C ++编译器负责确保即使弹出堆栈时异常数据也保持活动状态,因此不必觉得我们需要使用堆。
顺便说一句,抛出std :: string并不是开始的最佳方法。如果使用简单的包装器对象,那么我们将获得更大的灵活性。它可能暂时只是封装一个"字符串",但是将来可能我们会希望包含其他信息,例如导致异常的某些数据或者行号(非常常见)。我们不想在代码库的每个位置上更改所有异常处理,因此,现在就走高路,不要抛出原始对象。
一些原则:
- 我们有一个std :: exception基类,则应该从中派生异常。这样,通用异常处理程序仍然具有一些信息。
- 不要抛出指针而是对象,那样可以为我们处理内存。
例子:
struct MyException : public std::exception
{
std::string s;
MyException(std::string ss) : s(ss) {}
~MyException() throw () {} // Updated
const char* what() const throw() { return s.c_str(); }
};
然后在代码中使用它:
void Foo::Bar(){
if(!QueryPerformanceTimer(&m_baz)){
throw MyException("it's the end of the world!");
}
}
void Foo::Caller(){
try{
this->Bar();// should throw
}catch(MyException& caught){
std::cout<<"Got "<<caught.what()<<std::endl;
}
}
所有这些工作:
#include <iostream>
using namespace std;
//Good, because manual memory management isn't needed and this uses
//less heap memory (or no heap memory) so this is safer if
//used in a low memory situation
void f() { throw string("foo"); }
//Valid, but avoid manual memory management if there's no reason to use it
void g() { throw new string("foo"); }
//Best. Just a pointer to a string literal, so no allocation is needed,
//saving on cleanup, and removing a chance for an allocation to fail.
void h() { throw "foo"; }
int main() {
try { f(); } catch (string s) { cout << s << endl; }
try { g(); } catch (string* s) { cout << *s << endl; delete s; }
try { h(); } catch (const char* s) { cout << s << endl; }
return 0;
}
我们应该更喜欢h而不是f到g。请注意,在最不推荐使用的选项中,我们需要显式释放内存。
是的。 std :: exception是C ++标准库中的基本异常类。我们可能要避免将字符串用作异常类,因为它们本身在使用过程中会引发异常。如果发生这种情况,那么我们将在哪里?
boost具有出色的样式,可以很好地处理异常和错误。值得一读。
除了可能抛出从std :: exception派生的东西外,我们还应该抛出匿名临时对象并按引用进行捕获:
void Foo::Bar(){
if(!QueryPerformanceTimer(&m_baz)){
throw std::string("it's the end of the world!");
}
}
void Foo:Caller(){
try{
this->Bar();// should throw
}catch(std::string& caught){ // not quite sure the syntax is ok here...
std::cout<<"Got "<<caught<<std::endl;
}
}
- 我们应该抛出匿名临时对象,以便编译器处理所抛出对象的对象生存期-如果我们从堆中抛出新内容,则其他人需要释放该东西。
- 我们应该捕获引用以防止对象切片
。
有关详细信息,请参见Meyer的" Effective C ++第三版",或者访问https://www.securecoding.cert.org/.../ERR02-A.+Throw+anonymous+temporaries+and+catch+by+reference

