What's the purpose of using braces (i.e. {}) for a single-line if or loop?

前端 未结 23 1253
独厮守ぢ
独厮守ぢ 2020-11-28 00:33

I\'m reading some lecture notes of my C++ lecturer and he wrote the following:

  1. Use Indentation // OK
  2. Never rely on operator preced
相关标签:
23条回答
  • 2020-11-28 01:34

    I have my doubts as to the competence of the lecturer. Considering his points:

    1. OK
    2. Would anyone really write (or want to read) (b*b) - ((4*a)*c)? Some precedences are obvious (or should be), and the extra parentheses just add to confusion. (On the other hand, you _should_ use the parentheses in less obvious cases, even if you know that they're not needed.)
    3. Sort of. There are two wide spread conventions for formatting conditionals and loops:
      if ( cond ) {
          code;
      }
      
      and:
      if ( cond )
      {
          code;
      }
      
      In the first, I'd agree with him. The opening { is not that visible, so it's best to assume it's always there. In the second, however, I (and most of the people I've worked with) have no problem with omitting the braces for a single statement. (Provided, of course, that the indentation is systematic and that you use this style consistently. (And a lot of very good programmers, writing very readable code, omit the braces even when formatting the first way.)
    4. NO. Things like if ( NULL == ptr ) are ugly enough to hinder readability. Write the comparisons intuitively. (Which in many cases results in the constant on the right.) His 4 is bad advice; anything which makes the code unnatural makes it less readable.
    5. NO. Anything but int is reserved for special cases. To experienced C and C++ programmers, the use of unsigned signals bit operators. C++ doesn't have a real cardinal type (or any other effective subrange type); unsigned doesn't work for numeric values, because of the promotion rules. Numerical values on which no arithmetic operations would make sense, like serial numbers, could presumably be unsigned. I'd argue against it, however, because it sends the wrong message: bitwise operations don't make sense either. The basic rule is that integral types are int, _unless_ there is a significant reason for using another type.
    6. NO. Doing this systematically is misleading, and doesn't actually protect against anything. In strict OO code, delete this; is often the most frequent case (and you can't set this to NULL), and otherwise, most delete are in destructors, so you can't access the pointer later anyway. And setting it to NULL doesn't do anything about any other pointers floating around. Setting the pointer systematically to NULL gives a false sense of security, and doesn't really buy you anything.

    Look at the code in any of the typical references. Stroustrup violates every rule you've given except for the first, for example.

    I'd suggest that you find another lecturer. One who actually knows what he's talking about.

    0 讨论(0)
  • 2020-11-28 01:34

    It makes your code more readable by clearly defining the scope of your loops and conditional blocks. It also saves you from accidental mistakes.

    0 讨论(0)
  • 2020-11-28 01:34

    wrt 6: It's safer because deleteing a null pointer is a no-op. So if you happen to accidentally go through that path twice, you won't cause memory corruption be freeing memory that is either free or has been allocated to something else.

    This is most of an issue with static file scope objects and singletons that have not very clear lifetimes and have been known to get recreated after they've been destroyed.

    In most cases, you can avoid the need for this by using auto_ptrs

    0 讨论(0)
  • 2020-11-28 01:35

    It is best to set the pointer to NULL when you have finished with it.

    Here is an example why:

    Class A does the following:

    1. Allocates a block of memory
    2. Then some time later, it delete this block of memory but does not set the pointer to NULL

    Class B does the following

    1. Allocates memory (and in this instance it happens to be given the same memory block that was deleted by class A.)

    At this point both Class A and Class B have pointers pointing to the same memory block, as far as Class A is concerned this block of memory does not exists because it is finished with it.

    Consider the following problem:

    What if there was a logic error in Class A which resulted in it writing to memory that now belongs to Class B?

    In this particular instance, you will not get an bad access exception error because the memory address is legal, all the while class A is now effectively corrupting class B data.

    Class B may eventually crash if it encounters unexpected values and when it does crash, chances are, you will spend quite a long time hunting this bug in class B when the problem is in class A.

    If you had set the deleted memory pointer to NULL, you would have gotten an exception error as soon as any logic errors in Class A tried to write to NULL pointer.

    If you are worried about the logic error with double delete when pointers are NULL for the second time, then add assert for this.

    Also: If you are going to down vote, please explain.

    0 讨论(0)
  • 2020-11-28 01:36

    Looking through the answers no one's explicitly stated the sort of practice I make a habit of, telling the story of your code:

    int j = 0;
    for (int i = 0 ; i < 100 ; ++i)
    {
        if (i % 2 == 0)
        {
            j++;
        }
    }
    

    Becomes:

    int j = 0;
    for (int i = 0 ; i < 100 ; ++i)
    {
        if (i % 2 == 0) j++;
    }
    

    Putting the j++ on the same line as the if should signal to anyone else, "I only want this block to ever increment j". Of coursethis is only worthwhile if the line is as simplistic as possible, because putting a breakpoint here, as peri mentions, is not going to be very useful.

    In fact I've just run across part of the Twitter Storm API that has this 'sort' of code in java, here is the relvant snippet form the execute code, on page 43 of this slideshow:

    ...
    Integer Count = counts.get(word);
    if (Count=null) count=0;
    count++
    ...
    

    The for loop block has two things in it, so I wouldn't inline that code. I.e never:

    int j = 0;
    for (int i = 0 ; i < 100 ; ++i) if (i % 2 == 0) j++;
    

    It's awful and I don't even know if it works (as intended); don't do this. New lines and braces help distinguish separate but related pieces of code, in the same way a comma or a semi-colon do in prose. The above block is as bad a really long sentence with a few clauses and some other statements that never break or pause to distinguish separate parts.

    If you really want to telegraph to someone else it's a one-line only job use a ternary operator or ?: form:

    for (int i = 0 ; i < 100 ; ++i) (i%2 ? 0 : >0) j++;
    

    But this is verging on code-golf, and I think not great practice (It's not clear to me if I should put the j++ on one side of the : or not). NB I've not run a ternary operator in C++ before, I don't know if this works, but it does exist.

    In short:

    Imagine how your reader (i.e. the person maintaing the code) interprets your story (code). Make it as clear for them as possible. If you know the novice coder/student is maintaining this, perhaps even leave in as many {} as possible, just so they don't get confused.

    0 讨论(0)
提交回复
热议问题