代码之家  ›  专栏  ›  技术社区  ›  Palad1

C++异常:抛掷STD::字符串

  •  71
  • Palad1  · 技术社区  · 16 年前

    我想抛出一个例外,当我的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;
        }
    }
    
    7 回复  |  直到 7 年前
        1
  •  95
  •   christopher_f    12 年前

    对。 std::exception 是C++标准库中的基本异常类。您可能希望避免将字符串用作异常类,因为它们本身可以在使用期间引发异常。如果发生这种情况,你会在哪里?

    Boost有很好的 document 关于异常和错误处理的良好样式。值得一读。

        2
  •  57
  •   PierreBdR    11 年前

    一些原则:

    1. 您有一个std::exception基类,您应该从中派生异常。这样,常规异常处理程序仍然有一些信息。

    2. 不要抛出指针而是对象,这样内存就可以为您处理。

    例子:

    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;
      }
    }
    
        3
  •  20
  •   Patrick M    12 年前

    所有这些工作:

    #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。请注意,在最不可取的选项中,您需要显式地释放内存。

        4
  •  7
  •   Daniel Spiewak    16 年前

    它起作用了,但如果我是你,我就不会这么做了。完成后,您似乎没有删除堆数据,这意味着您已经创建了内存泄漏。C++编译器负责确保异常数据即使在堆栈被弹出时仍保持活力,所以不要觉得需要使用堆。

    顺便说一句,扔 std::string 不是最好的开始方法。如果您使用一个简单的包装器对象,那么在将来您将拥有更多的灵活性。它可能只是封装了一个 string 现在,但也许将来您会希望包括其他信息,比如导致异常的一些数据,或者一个行号(非常常见)。您不想在代码库中的每个地方更改所有异常处理,所以现在就走上正轨,不要抛出原始对象。

        5
  •  7
  •   Michael Burr    16 年前

    除了可能抛出从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的“有效C++第三版”的细节或访问 https://www.securecoding.cert.org/.../ERR02-A.+Throw+anonymous+temporaries+and+catch+by+reference

        6
  •  4
  •   Eric Leschinski Mr. Napik    11 年前

    在C++中抛出异常的最简单方法:

    #include <iostream>
    using namespace std;
    void purturb(){
        throw "Cannot purturb at this time.";
    }
    int main() {
        try{
            purturb();
        }
        catch(const char* msg){
            cout << "We caught a message: " << msg << endl;
        }
        cout << "done";
        return 0;
    }
    

    印刷品:

    We caught a message: Cannot purturb at this time.
    done
    

    如果捕获抛出的异常,则包含该异常,程序将继续运行。如果未捕获异常,则程序存在并打印:

    This application has requested the Runtime to terminate it in an unusual way. Please contact the application's support team for more information.

        7
  •  1
  •   GPMueller    7 年前

    尽管这个问题已经很老了,而且已经得到了解答,但我想在如何进行适当的异常处理方面添加一个注释。 在C++ 11中 :

    使用 std::nested_exception std::throw_with_nested

    在我看来,使用这些会导致更干净的异常设计,并且不需要创建异常类层次结构。

    请注意,这使您能够 对异常进行回溯 在代码内部,不需要调试程序或繁琐的日志记录。它在stackoverflow中描述 here here ,如何编写将重新引发嵌套异常的适当异常处理程序。

    由于可以对任何派生的异常类执行此操作,因此可以向此类回溯添加大量信息! 你也可以看看我的 MWE on GitHub ,其中回溯看起来像这样:

    Library API: Exception caught in function 'api_function'
    Backtrace:
    ~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
    ~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"