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

当抛出异常时,如果我不能承受缓慢的性能,我可以使用STL吗?

  •  8
  • Carl  · 技术社区  · 17 年前

    例如,我正在编写一个多线程的时间关键型应用程序,它可以实时处理和流式传输音频。音频中断是完全不可接受的。这是否意味着我不能使用STL,因为抛出异常时可能会减慢速度?

    7 回复  |  直到 8 年前
        1
  •  7
  •   Raedwald    8 年前

    在以前的答案中没有清楚地写出来,所以:

    异常发生在C++中

    使用stl或not不会删除raii代码,该代码将释放您分配的对象资源。

    例如:

    void doSomething()
    {
        MyString str ;
        doSomethingElse() ;
    }
    

    在上面的代码中,编译器将生成代码以释放mystring资源(即,将调用mystring析构函数),无论同时发生什么,包括如果dosomethingelse引发了异常,或者如果在函数范围结束之前执行了“返回”。

    如果你对此有问题,那么要么你应该改变你的思维方式,要么试试C。

    例外应该是例外

    通常,当发生异常时( and only when ,你会有一个性能冲击。

    但是,只有在以下情况下才应发送异常:

    • 您有一个异常事件需要处理(即某种错误)
    • 在非常特殊的情况下(即,从堆栈中的多个函数调用中“大量返回”,比如在执行复杂的搜索时,或者在线程正常中断之前展开堆栈)

    这里的关键字是“exception”,这很好,因为我们正在讨论“exception”(见模式?).

    在您的情况下,如果抛出了异常,那么很有可能是好的事情发生了,所以坏的事情发生了,您的程序无论如何都会毫无异常地崩溃。

    在这种情况下,您的问题不是处理性能问题。它是处理错误的优雅处理,或者更糟的是,程序的优雅终止(包括一个“抱歉”消息框,将未保存的数据保存到一个临时文件中以便以后恢复,等等)。

    这意味着(除非在非常特殊的情况下),不要将异常用作“返回数据”。当非常糟糕的事情发生时抛出异常。只有当你知道如何处理这个问题时,才能捕获一个异常。避免尝试/捕获(除非您知道如何处理异常)。

    STL怎么样?

    现在我们知道了:

    • 你还是想用C++
    • 你的目标不是为了取乐而每秒钟抛出一千个例外。

    我们应该讨论STL:

    STL通常会(如果可能的话)验证你是否做错了。如果你这样做,它会抛出一个异常。不过,在C++中,你通常不会为你不使用的东西付费。

    例如,访问向量数据。

    如果你 知道 你不会越界,那么你应该使用操作符[]。

    如果你 知道 您将不验证边界,然后应该使用()处的方法。

    例A:

    typedef std::vector<std::string> Vector ;
    
    void outputAllData(const Vector & aString)
    {
       for(Vector::size_type i = 0, iMax = aString.size() ; i != iMax ; ++i)
        {
           std::cout << i << " : " << aString[i] << std::endl ;
        }
    }
    

    实例B:

    typedef std::vector<std::string> Vector ;
    
    void outputSomeData(const Vector & aString, Vector::size_type iIndex)
    {
       std::cout << iIndex << " : " << aString.at(iIndex) << std::endl ;
    }
    

    示例A“信任”程序员,并且在验证过程中不会浪费时间(因此,引发异常的可能性更小) 那时 如果仍然有错误…这通常意味着错误/异常/崩溃通常会在之后发生,这对调试没有帮助,并且会让更多的数据损坏)。

    示例B要求向量验证索引是否正确,如果不正确则抛出异常。

    选择权属于你。

        2
  •  28
  •   Greg Rogers    17 年前

    通常,STL容器自己抛出的唯一例外是std::bad_c alloc(如果new失败)。只有在其他时间,用户代码(例如构造函数、赋值、复制构造函数)抛出。如果你的用户代码从来没有抛出,那么你只需要防止新的抛出,这是你最有可能不得不做的。

    其他可能引发异常的事情: -at()函数可以将std::抛出\u范围之外,如果您超出界限访问它们。无论如何,这是一个严重的程序错误。

    其次,例外并不总是缓慢的。如果您的音频处理中发生异常,可能是因为您无论如何都需要处理一个严重的错误。错误处理代码可能比将异常传输到catch站点的异常处理代码要贵得多。

        3
  •  8
  •   Nemanja Trifunovic    17 年前

    如果一个STL容器抛出,您可能会遇到比减速更大的问题:)

        4
  •  3
  •   Jeroen Dirks    17 年前

    不要害怕业绩方面的例外。

    在过去的C++中,启用异常的构建在某些编译器上可能会慢很多。

    这些天,不管您的构建是否有异常处理,它都是无关紧要的。

    一般来说,除非内存不足,否则STL不会抛出异常,因此对于您的应用程序类型来说,这也不应该是问题。

    (现在不要使用gc…..语言)

        5
  •  3
  •   Roddy    17 年前

    值得注意的几点是:

    • 您的应用程序是多线程的。如果一个线程(可能是一个GUI线程)因异常而减速,则不应影响实时线程的性能。

    • 例外情况适用于特殊情况。如果在实时线程中抛出异常,很可能意味着无论如何都无法继续播放音频。如果您发现无论出于什么原因,您都在不断地处理这些线程中的异常,请重新设计以首先避免这些异常。

    我建议您接受STL及其例外情况(除非STL本身证明太慢-但请记住: 先测量,后优化 )以及在应用程序中对自己的“异常情况”(音频硬件故障,无论什么)采用异常处理。

        6
  •  1
  •   Henk    17 年前

    我正在努力思考STL的哪些部分指定了它们可以引发异常。根据我的经验,大多数错误处理都是通过返回代码来处理的,或者作为STL使用的先决条件。 传递给STL的对象肯定会引发异常,例如复制构造函数,但不管使用STL,这都是一个问题。 其他人提到了诸如 std::vector::at() 但您通常可以执行检查或使用其他方法来确保不会引发异常。

    当然,STL的特定实现可以执行“检查”,通常对于调试构建,在您使用STL的基础上,我认为它只会引发断言,但可能有些会抛出异常。

    如果不存在try/catch,我相信除非您自己的类引发异常,否则不会发生任何/最小的性能损失。

    在VisualStudio上,可以完全禁用C++异常的使用 Project Properties -> C/C++ -> Code Generation -> Enable C++ Exceptions . 我认为这在大多数C++平台上都是可用的。

        7
  •  0
  •   James Curran    17 年前

    你说话的时候好像免责是不可避免的。只是不要做任何可能导致异常的事情——修复错误,验证输入。

    推荐文章