Google's style guide about input/output parameters as pointers

13,568

Solution 1

The reason for demanding that output parameters are passed as pointers is simple:

It makes it clear at the call site that the argument is potentially going to be mutated:

foo(x, y);     // x and y won't be mutated
bar(x, &y);    // y may be mutated

When a code base evolves and undergoes incremental changes that are reviewed by people who may not know the entire context all the time, it is important to be able to understand the context and impact of a change as quickly as possible. So with this style rule, it is immediately clear whether a change introduces a mutation.

Solution 2

The point they are making (which I disagree with) is that say I have some function

void foo(int a, Bar* b);

If the b argument is optional, or it is unnecessary sometimes, you can call the function like so

foo(5, nullptr);

If the function was declared as

void foo(int a, Bar& b);

Then there is no way to not pass in a Bar.

This point (emphasis mine) is completely opinion-based and up to the developer's discretion.

In fact it is a very strong convention in Google code that input arguments are values or const references while output arguments are pointers.

If I intend for b to be an output parameter, either of the following are perfectly valid and reasonable.

void foo(int a, Bar* b);  // The version Google suggests
void foo(int a, Bar& b);  // Reference version, also perfectly fine.

Solution 3

You're first question: "So, what's the point to always demand a pointer if I want to avoid the pointer to be null?"

Using a pointer announces to the caller that their variable may be modified. If I am calling foo(bar), is bar going to be modified? If I am calling foo(&bar) it's clear that the value of bar may be modified.
There are many examples of functions which take in a null indicating an optional output parameter (off the top of my head time is a good example.)

Your second question: "Why only use references for input arguments?"

Working with a reference parameter is easier than working with a pointer argument.

int foo(const int* input){
    int return = *input;

    while(*input < 100){
        return *= *input;
        (*input)++;
    }
}

This code rewritten with a reference looks like:

int foo(const int& input){
    int return = input;

    while(input < 100){
        return *= input;
        input++;
    }
}

You can see that using a const int& input simplifies the code.

Solution 4

They likely use it for consistency because they use output parameters both as references to existing memory (they're modifying previously initialized variables) and as actual outputs (the output arguments are assumed to be assigned by the function itself). For consistency, they use it as a way to more clearly indicate inputs vs. outputs.

If you never need a function/method to assign the memory of the output parameter, like returning a pointer from a lookup or allocating memory itself and returning it through a pointer, use references. If you need to do that but don't care about using pointers to act as an indication of whether a parameter is input or output, use references for output parameters when appropriate. There's no absolute requirement to use pointers in all cases unless the requirements of that function/method itself requires it.

Share:
13,568
suizokukan
Author by

suizokukan

French Teacher (French, Latin, Ancient Greek) o involved in numerous open source projects relating to dictionaries (Ancient Greek -&gt; French, Old English -&gt; French, Japanese -&gt; French). See my GitHub page. o member of the teachers writing for Musagora, a French site relating to Latin and Ancient Greek.

Updated on June 17, 2022

Comments

  • suizokukan
    suizokukan almost 2 years

    The Google C++ Style Guide draws a clear distinction (strictly followed by cpplint.py) between input parameters(→ const ref, value) and input-output or output parameters (→ non const pointers) :

    Parameters to C/C++ functions are either input to the function, output from the function, or both. Input parameters are usually values or const references, while output and input/output parameters will be non-const pointers.

    And further :

    In fact it is a very strong convention in Google code that input arguments are values or const references while output arguments are pointers.

    But I can't figure out why input/output arguments (I leave output arguments aside) should not be passed by reference. On stackoverflow there are plenty of topics related to this question : e.g. here, the accepted answer clearly say that

    it's mostly about style

    but that if

    you want to be able to pass null, you must use a pointer

    So, what's the point to always demand a pointer if I want to avoid the pointer to be null ? Why only use references for input arguments ?

    • molbdnilo
      molbdnilo over 9 years
      If it's not a pointer, you know it's not going to be modified. This is useful information. If out parameters can be references, or in parameters can be pointers, you need to either constantly look at the documentation or remember everything.
    • Christian Hackl
      Christian Hackl over 9 years
      Just because it's from Google doesn't mean it must make sense.
    • chris
      chris over 9 years
    • Lightness Races in Orbit
      Lightness Races in Orbit over 9 years
      The Google style guide contains a lot of nonsense. For example, it disallows ALL C++ exceptions.
  • chris
    chris over 9 years
    Titus seemed to lean more toward the callsite showing that whatever was passed in could be modified in his CppCon video.
  • suizokukan
    suizokukan over 9 years
    Thank you for your explanations : I understand it's "perfectly valid and reasonable" for the output arguments. But what about the input-output arguments ? I thought it was more dangerous to use pointers instead of references for them !
  • chris
    chris over 9 years
    @suizokukan, Nothing you said in your question suggests pointers for input parameters.
  • suizokukan
    suizokukan over 9 years
    Excuse me, it's not very clear to me and my English is so poor... By "input-output" argument I meant an argument modified by the function, not an input or an output argument.
  • Felix Bertoni
    Felix Bertoni almost 3 years
    I just want to mitigate a bit that maybe : let be a struct containing a pointer to an object. struct PtrStruct {int* a;}; Now I'm passing it by value. PtrStruct s; /* some setup */ foo(s);. My inner state can be mutated somehow, because I can access this inner pointer. What ensures non-mutability is more or less a combination of what the type is made of (pointers/refs or not, members private or not) and how it is passed (value/pointer/ref, const or not). That said, I still agree that the non non-const reference rule can make sense if set alongside rules to mitigate its use.