Use of 'const' for function parameters

前端 未结 30 2851
借酒劲吻你
借酒劲吻你 2020-11-22 03:06

How far do you go with const? Do you just make functions const when necessary or do you go the whole hog and use it everywhere? For example, imag

相关标签:
30条回答
  • 2020-11-22 03:41

    There is a good discussion on this topic in the old "Guru of the Week" articles on comp.lang.c++.moderated here.

    The corresponding GOTW article is available on Herb Sutter's web site here.

    0 讨论(0)
  • 2020-11-22 03:42

    1. Best answer based on my assessment:

    The answer by @Adisak is the best answer here based on my assessment. Note that this answer is in part the best because it is also the most well-backed-up with real code examples, in addition to using sound and well-thought-out logic.

    2. My own words (agreeing with the best answer):

    1. For pass-by-value there is no benefit to adding const. All it does is:
      1. limit the implementer to have to make a copy every time they want to change an input param in the source code (which change would have no side effects anyway since what's passed in is already a copy since it's pass-by-value). And frequently, changing an input param which is passed by value is used to implement the function, so adding const everywhere can hinder this.
      2. and adding const unnecessarily clutters the code with consts everywhere, drawing attention away from the consts that are truly necessary to have safe code.
    2. When dealing with pointers or references, however, const is critically important when needed, and must be used, as it prevents undesired side effects with persistent changes outside the function, and therefore every single pointer or reference must use const when the parm is an input only, not an output. Using const only on parameters passed by reference or pointer has the additional benefit of making it really obvious which parameters are pointers or references. It's one more thing to stick out and say "Watch out! Any param with const next to it is a reference or pointer!".
    3. What I've described above has frequently been the consensus achieved in professional software organizations I have worked in, and has been considered best practice. Sometimes even, the rule has been strict: "don't ever use const on parameters which are passed by value, but always use it on parameters passed by reference or pointer if they are inputs only."

    3. Google's words (agreeing with me and the best answer):

    (From the "Google C++ Style Guide")

    For a function parameter passed by value, const has no effect on the caller, thus is not recommended in function declarations. See TotW #109.

    Using const on local variables is neither encouraged nor discouraged.

    Source: the "Use of const" section of the Google C++ Style Guide: https://google.github.io/styleguide/cppguide.html#Use_of_const. This is actually a really valuable section, so read the whole section.

    Note that "TotW #109" stands for "Tip of the Week #109: Meaningful const in Function Declarations", and is also a useful read. It is more informative and less prescriptive on what to do, and based on context came before the Google C++ Style Guide rule on const quoted just above, but as a result of the clarity it provided, the const rule quoted just above was added to the Google C++ Style Guide.

    Also note that even though I'm quoting the Google C++ Style Guide here in defense of my position, it does NOT mean I always follow the guide or always recommend following the guide. Some of the things they recommend are just plain weird, such as their kDaysInAWeek-style naming convention for "Constant Names". However, it is still nonetheless useful and relevant to point out when one of the world's most successful and influential technical and software companies uses the same justification as I and others like @Adisak do to back up our viewpoints on this matter.

    4. Clang's linter, clang-tidy, has some options for this:

    A. It's also worth noting that Clang's linter, clang-tidy, has an option, readability-avoid-const-params-in-decls, described here, to support enforcing in a code base not using const for pass-by-value function parameters:

    Checks whether a function declaration has parameters that are top level const.

    const values in declarations do not affect the signature of a function, so they should not be put there.

    Examples:

    void f(const string);   // Bad: const is top level.
    void f(const string&);  // Good: const is not top level.
    

    And here are two more examples I'm adding myself for completeness and clarity:

    void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
    void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]
    

    B. It also has this option: readability-const-return-type - https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html

    5. My pragmatic approach to how I'd word a style guide on the matter:

    I'd simply copy and paste this into my style guide:

    [COPY/PASTE START]

    1. Always use const on function parameters passed by reference or pointer when their contents (what they point to) are intended NOT to be changed. This way, it becomes obvious when a variable passed by reference or pointer IS expected to be changed, because it will lack const. In this use case const prevents accidental side effects outside the function.
    2. It is not recommended to use const on function parameters passed by value, because const has no effect on the caller: even if the variable is changed in the function there will be no side effects outside the function. See the following resources for additional justification and insight:
      1. "Google C++ Style Guide" "Use of const" section
      2. "Tip of the Week #109: Meaningful const in Function Declarations"
      3. Adisak's Stack Overflow answer on "Use of 'const' for function parameters"
    3. "Never use top-level const [ie: const on parameters passed by value] on function parameters in declarations that are not definitions (and be careful not to copy/paste a meaningless const). It is meaningless and ignored by the compiler, it is visual noise, and it could mislead readers" (https://abseil.io/tips/109, emphasis added).
      1. The only const qualifiers that have an effect on compilation are those placed in the function definition, NOT those in a forward declaration of the function, such as in a function (method) declaration in a header file.
    4. Never use top-level const [ie: const on variables passed by value] on values returned by a function.
    5. Using const on pointers or references returned by a function is up to the implementer, as it is sometimes useful.
    6. TODO: enforce some of the above with the following clang-tidy options:
      1. https://clang.llvm.org/extra/clang-tidy/checks/readability-avoid-const-params-in-decls.html
      2. https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html

    Here are some code examples to demonstrate the const rules described above:

    const Parameter Examples:
    (some are borrowed from here)

    void f(const std::string);   // Bad: const is top level.
    void f(const std::string&);  // Good: const is not top level.
    
    void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
    void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]
    

    const Return Type Examples:
    (some are borrowed from here)

    // BAD--do not do this:
    const int foo();
    const Clazz foo();
    Clazz *const foo();
    
    // OK--up to the implementer:
    const int* foo();
    const int& foo();
    const Clazz* foo();
    

    [COPY/PASTE END]

    0 讨论(0)
  • 2020-11-22 03:43

    I do not use const for value-passed parametere. The caller does not care whether you modify the parameter or not, it's an implementation detail.

    What is really important is to mark methods as const if they do not modify their instance. Do this as you go, because otherwise you might end up with either lots of const_cast<> or you might find that marking a method const requires changing a lot of code because it calls other methods which should have been marked const.

    I also tend to mark local vars const if I do not need to modify them. I believe it makes the code easier to understand by making it easier to identify the "moving parts".

    0 讨论(0)
  • 2020-11-22 03:46

    Ah, a tough one. On one side, a declaration is a contract and it really does not make sense to pass a const argument by value. On the other hand, if you look at the function implementation, you give the compiler more chances to optimize if you declare an argument constant.

    0 讨论(0)
  • 2020-11-22 03:46

    To summarize:

    • "Normally const pass-by-value is unuseful and misleading at best." From GOTW006
    • But you can add them in the .cpp as you would do with variables.
    • Note that the standard library doesn't use const. E.g. std::vector::at(size_type pos). What's good enough for the standard library is good for me.
    0 讨论(0)
  • 2020-11-22 03:46

    the thing to remember with const is that it is much easier to make things const from the start, than it is to try and put them in later.

    Use const when you want something to be unchanged - its an added hint that describes what your function does and what to expect. I've seen many an C API that could do with some of them, especially ones that accept c-strings!

    I'd be more inclined to omit the const keyword in the cpp file than the header, but as I tend to cut+paste them, they'd be kept in both places. I have no idea why the compiler allows that, I guess its a compiler thing. Best practice is definitely to put your const keyword in both files.

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