在C ++社区有什么应该使用异常的一般共识吗? [英] Is there a general consensus in the C++ community on when exceptions should be used?

查看:159
本文介绍了在C ++社区有什么应该使用异常的一般共识吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚花了几个小时阅读关于什么时候使用异常的问题的问题,似乎有两个阵营有不同的观点:


  1. 在错误代码中使用异常

  2. 大部分时间使用错误代码,只有当发生一些灾难性错误时才会出现异常

  3. <

    这只是一个有争议的话题,没有被广泛接受的最佳做法?

    解决方案

    您可以从丰富的答案中收集,肯定没有一致。



    语义上,异常和错误提供完全相同的功能。实际上,它们在所有语义方面都是相同的,错误可以像异常那样任意丰富(你不必使用简单的代码,你可以使用一个真正的数据包!)。



    唯一的区别是他们的传播方法:




    • 错误必须手动传递

    • 异常自动传播



    另一方面:




    • 签名中完全记录了错误的可能性。

    • 代码检查中的静音(读取 GotW#20:Code Complexity and cry)和隐藏的执行路径使得推理更加困难。



    两个解决方案都可以看起来很笨重的原因只是错误检查很难。事实上,我每天写的大部分代码都涉及错误检查,无论是技术还是功能。



    那么该怎么办?

    $警告:向前示范,如果您只关心答案,请转到下一部分



    我个人喜欢在这里利用类型系统。典型的例子是指针参考二分法:一个指针就像一个可以为null的引用(并且被重新引用,但这并不重要)



    因此,而不是:

      //异常规范最好不要用于C ++ 
    //这些只是为了表示存在例外
    Object const& Container :: search(Key const& key)const throw(NotFound);

    我会倾向于写:

      Object const * Container :: search(Key const& key)const; 

    或者更好的是,使用聪明的指针:

     指针< Object const> Container :: search(Key const& key)const; 

    模板< typename O>
    O *指针< O> :: operator->()const throw(Null);

    模板< typename O>
    O&指针< O> :: operator *()const throw(Null);

    这里我发现使用异常多余的原因有两个:




    • 如果我们正在搜索一个对象,那么没有发现它是一个很常见的事情,并且没有太多的数据可以携带:导致错误?

    • 客户不一定认为它是不存在的错误,我认为我认为她的业务比她好是吗我是谁决定永远不会是不适合不要找到所需要的情况?



    我本身没有异常的问题,但是他们可以使代码尴尬,考虑:

      void noExceptions(Container const& c)
    {
    指针< Object const> o = c.search(my-item);

    if(!o){
    o = c.search(my-other-item);
    }

    if(!o){return; } //没有什么可以做的

    //用o
    做某事

    并将其与异常情况进行比较:

      void exceptions(Container const& c)
    {
    Object const * p = 0;
    try {
    p =& c.search(my-item);
    }
    catch(NotFound const&){
    try {
    p =& c.search(my-other-item);
    }
    catch(NotFound const&){
    return; //没有什么可以做的
    }
    }

    //用p
    做某事

    在这种情况下,使用异常似乎不合适:/



    另一方面: p>

      try {
    print()<< 我可爱的小宝宝< baby.name()<< 重量< baby.weight();
    }
    catch(Oupsie const&){
    // deal
    }

    肯定比以下更有吸引力:

      if(!print(My cute little baby)) {/ * deal * /} 
    if(!print(baby.name())){/ * deal * /}
    if(!print(weights)){/ * deal * }
    if(!print(baby.weight())){/ * deal * /}






    最好的是什么?



    这取决于。像所有的工程问题一样,没有任何银弹,这一切都是关于让步。



    所以要记住两件事:




    • 错误报告是API的一部分

    • 应该设计易于使用的API



    如果您发现自己想知道是否使用异常,请尝试使用您的API。如果没有明确的优胜者,那就是这样:没有理想的解决方案。



    呵呵,不要犹豫重构你的API,在制定时选出的错误报告机制已不再适用。不要羞愧:要求随时间而变化,所以API随之改变是正常的。



    我个人我倾向于使用例外对于不可恢复的错误:我因此在我的代码中几乎没有try / catch,只能在最外层,准确地记录错误(爱堆栈框架),并记录BOM的转储。



    这是Haskell非常相似(并且受到很大的影响),代码在两个明确的部分中被分离:尽管任何可以抛出异常,但只有IO部分(外部的)可能实际上捕获它们。因此,纯粹的部分必须以其他方式处理错误条件,以防它们正常。



    但是,如果我遇到使用异常的问题使代码更容易阅读,更自然(这是主观的)然后我使用一个例外:)


    I just spent a few hours reading through SO questions on the topic of when to use exceptions, and it seems like there are two camps with different point of views:

    1. Use exceptions over error codes
    2. Use error codes most of the time, and exceptions only when some catastrophic error occurs

    Is this just a controversial topic with no widely accepted best practice?

    解决方案

    As you can probably gather from the wealth of answers, there is certainly no consensus.

    Semantically, exceptions and error provide the exact same functionality. Indeed they are identical in about all semantic aspects, and errors can be arbitrarily enriched much like exceptions (you don't have to use a simple code, you can use a real bundle of data!).

    The only difference there is is their propagation methods:

    • errors have to be passed down manually
    • exceptions are propagated automatically

    On the other hand:

    • the possibility of an error is perfectly documented in the signature
    • exceptions are silent on code inspection (read GotW #20: Code Complexity and cry) and hidden paths of execution make reasoning harder.

    The very reason both solutions can appear clunky is simply that error checking is difficult. Indeed most of the code I am writing daily concerns error checking, whether technical or functional.

    So what to do ?

    Warning: demonstration ahead, jump over to the next section if you care only for an answer

    I personally like to leverage the type system here. The typical example is the pointer-reference dichotomy: a pointer is like a reference that can be null (and reseated, but it does not matter here)

    Therefore, instead of:

    // Exceptions specifications are better not used in C++
    // Those here are just to indicate the presence of exceptions
    Object const& Container::search(Key const& key) const throw(NotFound);
    

    I will tend to write:

    Object const* Container::search(Key const& key) const;
    

    Or better yet, using clever pointers:

    Pointer<Object const> Container::search(Key const& key) const;
    
    template <typename O>
    O* Pointer<O>::operator->() const throw(Null);
    
    template <typename O>
    O& Pointer<O>::operator*() const throw(Null);
    

    Here I find the use of exception superfluous for 2 reasons:

    • If we are searching for an object, then there not finding it is both a perfectly common occurrence and there is not much data to carry about: cause of error ? it is not there
    • The client does not necessarily consider it an error that it is not there, who am I to assume that I know her business better than she does ? Who am I to decide that there will never be a case where it won't be appropriate not to find what was asked for ?

    I don't have a problem with exceptions per se, but they can make the code awkward, consider:

    void noExceptions(Container const& c)
    {
      Pointer<Object const> o = c.search("my-item");
    
      if (!o) {
        o = c.search("my-other-item");
      }
    
      if (!o) { return; } // nothing to be done
    
      // do something with o
    }
    

    And compare it with the "exception" case:

    void exceptions(Container const& c)
    {
      Object const* p = 0;
      try {
        p = &c.search("my-item");
      }
      catch(NotFound const&) {
        try {
          p = &c.search("my-other-item");
        }
        catch(NotFound const&) {
          return; // nothing to be done
        }
      }
    
      // do something with p
    }
    

    In this case, the use of exceptions does not seem appropriate :/

    On the other hand:

    try {
     print() << "My cute little baby " << baby.name() << " weighs " << baby.weight();
    }
    catch(Oupsie const&) {
      // deal
    }
    

    is certainly more appealing than:

    if (!print("My cute little baby ")) { /*deal*/ }
    if (!print(baby.name())) { /*deal*/ }
    if (!print(" weighs ")) { /*deal*/ }
    if (!print(baby.weight())) { /*deal*/ }
    


    What is the best then ?

    It depends. Like all engineering problem there is no silver bullet, it's all about concessions.

    So keep 2 things in mind:

    • Error reporting is part of the API
    • APIs should be designed with ease of use in mind

    If you find yourself wondering whether to use an exception or not, just try to use your API. If there is no clear cut winner, it is just that: there is no ideal solution.

    Oh, and do not hesitate to refactor your API when it becomes clear that the error reporting mechanism elected at the time of crafting it is no longer appropriate. Don't be ashamed: requirements change with time, so it is normal that the API change with them.

    Personally I tend to use exceptions for unrecoverable errors only: I therefore have few try/catch in my code, only in the outermost levels, to accurately log the error (love stack frames) and log a dump of the BOM as well.

    This is very similar (and indeed strongly influenced) by Haskell, the code there is seggregated in two clear cut parts: while any can throw exceptions, only the IO part (the extern one) may actually catch them. Therefore, the pure part must deal with error conditions with other ways in case they are "normal".

    If, however, I am faced with a problem where using an exception makes the code easier to read and more natural (which is subjective) then I use an exception :)

    这篇关于在C ++社区有什么应该使用异常的一般共识吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆