C++ function parameters: use a reference or a pointer (and then dereference)?

后端 未结 11 2214
臣服心动
臣服心动 2021-02-05 10:49

I was given some code in which some of the parameters are pointers, and then the pointers are dereferenced to provide values. I was concerned that the pointer dereferencing wou

相关标签:
11条回答
  • 2021-02-05 11:13

    If you need to do things like bellow to remember that "a" is going to be changed on the function. What will stop you from inverting parameters that have same type or making some nasty error, when you have to call some function you must keep the prototype on your memory, or use some IDE that show it on a tooltip. There no excuse for that, I don't like references because I cant know if the function will change it, is not an valid argument.

    MyFunc2(/*&*/a, /*&*/b)
    
    0 讨论(0)
  • 2021-02-05 11:18

    From a performance perspective, any competent compiler should wipe out the issue, which is highly unlikely to be a bottleneck in any case. If you're genuinely working at that low a level, assembly code analysis and performance profiling on realistic data are going to be essential parts of your toolkit anyway.

    From a maintenance perspective, you really shouldn't allow someone to pass in parameters as pointers without checking them for nullity.

    So you end up writing a ton of null check code, for no good reason.

    Basically it goes from:

    1. Create object
    2. Pass in as non-const reference

    To:

    1. Create object
    2. Get address of object
    3. Pass in address
    4. Check if address points to null
    5. Dereference back to a non-const reference for use throughout the function

    While the compiler will parse all of that junk out, the reader of the code won't. It'll be extra code to consider when extending the functions or working out what the code does. Also more code is written, which increases the number of lines that can contain a bug. And as it's pointers, the bugs are more likely to be quirky undefined behaviour bugs.

    It also encourages weaker programmers to write code like this:

    int* a = new int(4); // Don't understand why this has to be a pointer
    int* b = new int(5); // Don't understand why this has to be a pointer
    MyFunc2(a, b);
    int& a_r = *a;
    int& b_r = *b;
    

    Yes, that's terrible, but I've seen it from new coders who don't really understand the pointer model.

    At the same time, I'd argue that the whole "I can see whether it's going to be modified without looking at the actual header", is a bit of a false advantage, considering the potential losses. If you can't immediately tell which are the output parameters from the context of the code, then that's your problem, and no amount of pointers are going to save you. If you must have an & to identify your output parameters, may I introduce:

    MyFunc2(/*&*/a, /*&*/b)
    

    All the "readability" of the ampersand, none of the associated pointer risks.

    However, when it comes to maintenance, consistency is king. If there is existing code that you're integrating with, that passes as pointers (e.g. the other functions of the class or library), there's no good reason to be a crazy rebel and go your own way. That's really going to cause confusion.

    0 讨论(0)
  • 2021-02-05 11:19

    You can get the assembly code from your compiler and compare them. At least in GCC, they produce identical code.

    0 讨论(0)
  • 2021-02-05 11:21

    There are different guidelines on using reference vs. pointer parameters out there, tailored to different requirements. In my opinion, the most meaningful rule that should be applied in generic C++ development is the following:

    1. Use reference parameters when overloading operators. (In this case you actually have no choice. This is what references were introduced for in the first place.)

    2. Use const-reference for composite (i.e. logically "large") input parameters. I.e input parameters should be passed either by value ("atomic" values) or by const-reference ("aggregate" values). Use pointers for output parameters and input-output parameters. Do not use references for output parameters.

    Taking the above into the account, the overwhelming majority of reference parameters in your program should be const-references. If you have a non-const reference parameter and it is not an operator, consider using a pointer instead.

    Following the above convention, you'll be able to see at the point of the call whether the function might modify one of its arguments: the potentially modified arguments will be passed with explicit & or as already-existing pointers.

    There's another popular rule out there that states that something that can be null should be passed as a pointer, while something that can't be null should be passed as a reference. I can imagine that this might make sense in some very narrow and very specific circumstances, but in general this is a major anti-rule. Just don't do it this way. If you want to express the fact that some pointer must not be null, put a corresponding assertion as the very first line of your function.

    As for the perfromance considerations, there's absolutely no performance difference in passing by pointer or passing by reference. Both kinds of parameters are exactly the same thing at the physical level. Even when the function gets inlined, a modern compiler should be smart enough to preserve the equivalence.

    0 讨论(0)
  • 2021-02-05 11:23

    From a performance point of view, it probably doesn't matter. Others have already answered that.

    Having said that, I have yet not found a situation where an added instruction in this case would make a noticeable difference. I do realize that for a function that is called billions of times, it could make a difference. As a rule, you shouldn't adapt your programming style for these kind of "optimizations".

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