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

4

17

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 ?

Selfabnegation answered 18/10, 2014 at 15:10 Comment(5)
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.Ratty
Just because it's from Google doesn't mean it must make sense.Coiffure
FWIW, Titus's CppCon talkReflux
The Google style guide contains a lot of nonsense. For example, it disallows ALL C++ exceptions.Decimal
The Google C++ style guide appears to have changed. "Non-optional input parameters should usually be values or const references, while non-optional output and input/output parameters should usually be references (which cannot be null)"Canvasback
I
39

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.

Interface answered 18/10, 2014 at 16:4 Comment(5)
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.Curcuma
@FelixBertoni: In C, if your struct has pointers, don't consider the pointed values as inner state. It's not, this is broken thinking. The most you can do to prevent modifying the pointed-to state is to make the member a const-pointer. But this has other issues, in general the use of const has a lot of caveats.Koroseal
@FelixBertoni: And in C++, you can actually provide the illusion of encapsulated inner state -- to a degree. Only hand out a non-const pointer from a non-const method. From const methods, only hand out const pointers, even though the (private) pointer is non-const internally.Koroseal
@JoSo My point (poorly explained tho), was that in C++, forbidding non-const references isn't sufficient to ensure immutability through compiler checks, if the passed-by-const-ref structure contains non const pointers or references. Having a convention of using const-ref vs non const pointer to differentiate mutability of parameters is not as strong as a compiler-checked solution, but still quite elegant.Curcuma
@JoSo I was not talking about C but trying to provide a quick example for C++ ^^ That said, C semantics being extremely limited when it comes to express immutability, it can eventually be better to assume stuff (for example inner state) and to enforce simple conventions (for example : always make a copy before modifying data) rather than trying to express things solely through semantics of the language. Best would be to have no pointers at all, but it can be problematic in case where performance is critical. I kinda agree tho, assumed inner state pointer is still to be avoided if possible.Curcuma
W
9

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.
Warder answered 18/10, 2014 at 15:17 Comment(4)
Titus seemed to lean more toward the callsite showing that whatever was passed in could be modified in his CppCon video.Reflux
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 !Selfabnegation
@suizokukan, Nothing you said in your question suggests pointers for input parameters.Reflux
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.Selfabnegation
A
4

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.

Abbreviation answered 18/10, 2014 at 15:52 Comment(0)
R
1

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.

Rucker answered 18/10, 2014 at 15:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.