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