523

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, imagine a simple mutator that takes a single boolean parameter:

void SetValue(const bool b) { my_val_ = b; }

Is that const actually useful? Personally I opt to use it extensively, including parameters, but in this case I wonder if it's worthwhile?

I was also surprised to learn that you can omit const from parameters in a function declaration but can include it in the function definition, e.g.:

.h file

void func(int n, long l);

.cpp file

void func(const int n, const long l)

Is there a reason for this? It seems a little unusual to me.

Michael Myers
  • 188,989
  • 46
  • 291
  • 292
Rob
  • 76,700
  • 56
  • 158
  • 197
  • I disagree. The .h file must have the const definitions as well. If not, then if const parameters are passed to the function, the compiler will generate an error, as the prototype in the .h file does not have the const definitions. – selwyn Sep 25 '08 at 20:31
  • 15
    I agree. :-) (With the question, not the last comment!) If a value shouldn't be changed in the body of the function, this can help stop silly == or = bugs, you should never put const in both,(if it's passed by value, you must otherwise) It's not serious enough to get into arguments about it though! – Chris Huang-Leaver Apr 20 '09 at 14:24
  • 27
    @selwyn: Even if you pass a const int to the function, though, it is going to be copied (since it's not a reference), and so the const-ness doesn't matter. – jalf May 04 '09 at 23:20
  • 1
    Same debate happening in this question: http://stackoverflow.com/questions/1554750/c-const-keyword-use-liberally – Partial Nov 12 '09 at 15:34
  • 7
    I realize this post is a couple years old, but as a new programmer, I was wondering this very question and I stumbled upon this conversation. In my opinion, if a function shouldn't change a value, whether its a reference or a copy of the value/object, it should be const. It's safer, it's self-documenting, and it's more debug friendly. Even for the simplest function, which has one statement, I still use const. –  Sep 19 '11 at 20:45
  • Now with move semantics having const could come at a performance cost – Jimmy R.T. Dec 18 '20 at 14:41

31 Answers31

526

const is pointless when the argument is passed by value since you will not be modifying the caller's object.

Wrong.

It's about self-documenting your code and your assumptions.

If your code has many people working on it and your functions are non-trivial then you should mark const any and everything that you can. When writing industrial-strength code, you should always assume that your coworkers are psychopaths trying to get you any way they can (especially since it's often yourself in the future).

Besides, as somebody mentioned earlier, it might help the compiler optimize things a bit (though it's a long shot).

Enlico
  • 23,259
  • 6
  • 48
  • 102
rlerallut
  • 7,545
  • 5
  • 23
  • 21
  • 56
    Totally agree. It's all about communicating with people and restricting what could be done with a variable to what should be done. – Len Holgate Sep 22 '08 at 21:08
  • 36
    I've voted this one down. I think you dilute what you're trying to indicate with const when you apply it to simple pass by value arguments. – tonylo Sep 23 '08 at 08:02
  • 37
    I've voted this one up. Declaring the parameter 'const' adds semantic information to the parameter. They highlight what the original author of the code had intended and this will aid maintenance of the code as time goes by. – Richard Corden Sep 23 '08 at 08:20
  • 18
    @tonylo: you misunderstand. This is about marking a local variable as const inside a block of code (that happens to be a function). I would do the same for any local variable. It is orthogonal to having an API that is const-correct, which is indeed also important. – rlerallut Sep 23 '08 at 08:50
  • 5
    Not really, I think you're just overestimating the usefulness of const. I think [the usefulness] it kicks in when the ownership of a object is important to define. Take a look at POSIX APIs, open(2) for e.g. the pathname (pointer) is worthwhile making const, for the flags and modes it's irrelevant. – tonylo Sep 23 '08 at 23:17
  • 71
    And it can catch bugs *inside* the function -- if you know that a parameter shouldn't be changed, then declaring it const means that the compiler will tell you if you accidently modify it. – Adrian Oct 01 '08 at 01:03
  • 3
    @tonylo, i'm being rather neutral to this issue. If people put const in parameters, good. But i don't do it in my code. But mentioning manpages `open` and so on isn't really an argument. Because the `const` wouldn't be part of the interface. So it would be wrong to show the `const` in manpages. – Johannes Schaub - litb Oct 13 '09 at 09:07
  • @Partial, i do not disagree with you in that it's never wrong to write it. But it's also not wrong to not always stick it everywhere. There are cases where i find the benefit doesn't justify it. This is a personal opinion: You will never see me downvoting any such answer just because of my personal opinion, and you will never read me writing that putting const anywhere is wrong. – Johannes Schaub - litb Nov 17 '09 at 22:28
  • 8
    But it limits your choice of algorithms (or forces you to make unnecessary copies) - if I call your sin(x) I don't care if your sin() algorithm should change it's copy of X while it's evaluating the answer. – Martin Beckett Sep 15 '10 at 04:45
  • 6
    I agree with you that const should be used as much as possible, but the const should not be in the header file because the user of an interface is not interested in what is done internally in the body of a method / function with parameter passed by value. – Giorgio Sep 12 '11 at 12:03
  • 4
    "Reductio ad absurdum" - the answer calls to use 'const' whenever you can. This just leads to cluttered API's that are harder to read and limits algorithms. `void bytecopy(char * CONST dest, const char * CONST source, CONST int count) { while(count--) { *dest++=*source++; } }` won't work and three of the four consts (the capitalized ones) are unnecessary. – Adisak Jun 14 '12 at 15:51
  • 9
    "You should always assume that your coworkers are psychopaths trying to get you any way they can" made me laugh out loud at work. +1 for that. – Cody Piersall Jun 26 '13 at 14:15
  • 4
    If your coworkers are psychopaths, expect them to write `struct Foo { void bar(const string); }; void Foo::bar(string s) { s = "I modified a string which was supposed to be const"; }` So much for self-documenting. – Oktalist Feb 08 '14 at 23:51
  • 2
    -1 for what Oktalist said, there are psychopaths and then there are const psychopaths. Often they are one and the same schizophrenic. If you ever cast const away just once anywhere in your const-correct code, all assumptions about self-documenting code falls apart as you can no longer trust the API. – CodeSmile Jul 25 '14 at 06:20
  • For me there is also another reason to write const at this point. I do this for consistent reasons. I made myself the habit to make parameters const by default, so why stopping at POD types? (just my personal opinion) – Milania May 27 '15 at 18:57
  • 5
    I think using const with non reference/pointer parameters, is the same as surrounding return statement with parentheses. – mike Sep 10 '16 at 18:51
  • Agreed wholeheartedly! real API developer use const. – sailfish009 Feb 05 '18 at 00:10
  • 4
    What is missing from this discussion is the distinction between the interface contract and the implementation. Adding const to a by-value parameter in a method declaration doesn't change the semantics of the interface and hence can't signal anything to the client - constness isn't part of the contract. It would be useful to include it in the definition, signaling to future implementers that it wasn't intended to be changed within the implementation. It is possible to use const in the declaration without const in the definition. by-value const in the interface is unnecessary clutter. – DavidJ Jun 28 '18 at 18:38
  • 1
    Let me disagree with your answer here @rlerallut (even though it is 10 years old now). A const in the header for by-value arguments provides no - or even negative - value. On the one hand it is not enforced by the compiler, so nothing stops a developer from removing the "const" in the implementation (and then forgetting to update the header). On the other hand the user of the header has no benefit to know that the function (supposedly - see before) uses the value in a const way. At best it is noise in the header, at worst it implies promises which the implementer can easily break. – CharonX Dec 17 '18 at 15:21
  • If only const was the default option and you had to go out of your way to make a parameter mutable by prefixing it with a keyword. The existing C++ syntax seems akin to how in TypeScript you have to write extra syntax to use strong typing! – Sphynx Jan 04 '19 at 22:02
241

The reason is that const for the parameter only applies locally within the function, since it is working on a copy of the data. This means the function signature is really the same anyways. It's probably bad style to do this a lot though.

I personally tend to not use const except for reference and pointer parameters. For copied objects it doesn't really matter, although it can be safer as it signals intent within the function. It's really a judgement call. I do tend to use const_iterator though when looping on something and I don't intend on modifying it, so I guess to each his own, as long as const correctness for reference types is rigorously maintained.

PiCTo
  • 924
  • 1
  • 11
  • 23
Greg Rogers
  • 35,641
  • 17
  • 67
  • 94
  • 76
    I can't agree with the 'bad style' part. Dropping `const` from function prototypes has the advantage that you don't need to alter the header file if you decide to drop `const` from implementation part later. – Michał Górny Jan 09 '10 at 11:53
  • 11
    "I personally tend to not use const except for reference and pointer parameters." Maybe you should clarify that to "I tend not to use superfluous qualifiers in function declarations, but use `const` where it makes a useful difference." – Deduplicator Sep 09 '14 at 16:53
  • 8
    I disagree with this answer. I lean the other way and mark parameters `const` whenever possible; it's more expressive. When I read someone else's code, I use little indicators like this to judge how much care they put into writing their code alongside things like magic numbers, commenting, and proper pointer usage, etc. – Ultimater Aug 01 '16 at 20:27
  • 5
    `int getDouble(int a){ ++a; return 2*a; }` Try this. Of course, the `++a` has nothing to do there but it _can_ be found there in a long function written by more than one programmer over a long period of time. I would strongly suggest to write `int getDouble( const int a ){ //... }` that will generate a compile error when finding `++a;`. – dom_beau Mar 27 '17 at 03:58
  • 13
    It is all a matter of who needs which information. You provide the parameter **by value** so the caller **does not need to know anything** on what you do (internally) with it. So write `class Foo { int multiply(int a, int b) const; }` in your header. In your implementation **you do care** that you can promise not to alter `a` and `b` so `int Foo::multiply(const int a, const int b) const { }` makes sense here. (Sidenote: both the caller and the implementation care about the fact that the function does not alter its `Foo` object, thus the const at the end of its declaration) – CharonX Oct 01 '18 at 09:54
  • 1
    I also don't think this "answer" is fair in either thinking it is bad style, that it doesn't really matter. There is some practical truth to judgement call but all the arguments for const in the general case of a variable apply and it's a language issue / oversight that this isn't dealt with differently for a declaration. I would say I'm not happy with "the bad side" explanations I see elsewhere (which have other side effects). It's was bad of stackoverflow for selecting this as the answer, not that it can't be part of a larger answer, but that it is incomplete to a complex issue of c++. – Jason Newton Jun 05 '19 at 05:11
  • 1
    @MichałGórny just imagine first line of your function as void func(unsigned char const * const buffer , size_t const length ); , it looks clumsy .But instead if we write as void func(unsigned char const * buffer , size_t length ); , it looks much better – Abhishek Garg Nov 26 '19 at 11:11
  • 1
    It may be worth noting that Stroustrup (at least in _TC++PL 4th Ed._) uses `const` only for pointer and reference parameters. His main comment on pass-by-value `const` is that there is no danger of modifying the calling context whether `const` is used or not (see pg. 308). One argument against by-value `const` is simply that worrying about it takes a certain amount of time and energy that might be better spent in more significant places—your functions should be short and clear enough that you can easily keep track of what's happening to the parameters anyway. – Zoë Sparks Oct 28 '20 at 09:55
  • In a header file, adding const to arguments passed by value only increases the cognitive load of using the header's functions. I end up asking myself whether the const means anything to a caller of the function. Even if the answer to that question is immediate and obvious, it's still one more thing I had to consider. In a function definition in a .c file it can be a useful safeguard, but not in a header. I assume that's why most (all?) C compilers allow pass-by-value const to differ between the declaration and the definition. – Darryl Feb 20 '23 at 18:29
180

Sometimes (too often!) I have to untangle someone else's C++ code. And we all know that someone else's C++ code is a complete mess almost by definition :) So the first thing I do to decipher local data flow is put const in every variable definition until compiler starts barking. This means const-qualifying value arguments as well, because they are just fancy local variables initialized by caller.

Ah, I wish variables were const by default and mutable was required for non-const variables :)

anatolyg
  • 26,506
  • 9
  • 60
  • 134
Constantin
  • 27,478
  • 10
  • 60
  • 79
  • 9
    "I wish variables were const by default" - an oxymoron?? 8-) Seriously, how "consting" everything helps you untangle code? If original writer changed a supposedly constant argument, how do you know that the var was supposed to be a constant? Moreover, vast majority of the (non-argument) variables are meant to be... variables. So compiler should break very soon after you started the process, no? – ysap Jan 23 '17 at 07:59
  • 16
    @ysap, 1. Marking const as much as possible lets me see which parts are moving and which are not. In my experience, many locals are de facto const, not the other way around. 2. "Const variable"/"Immutable variable" may sound as oxymoron, but is standard practice in functional languages, as well as some non-functional ones; see Rust for example: https://doc.rust-lang.org/book/variable-bindings.html – Constantin Jan 29 '17 at 16:49
  • 2
    Also standard now in some circumstances in c++; for example, the lambda `[x](){return ++x;}` is an error; see [here](https://stackoverflow.com/q/5501959/509868) – anatolyg Jun 21 '17 at 14:08
  • 22
    Variables are "`const`" by default in [Rust](https://www.rust-lang.org/) :) – phoenix Jul 31 '17 at 12:46
  • Variables need not necessarily be assignables to allow them to vary; the value they are initialized with can also vary at runtime. – Sphynx Jan 04 '19 at 22:14
  • 1
    @phoenix For the future reader: [*Why is immutability enforced in Rust unless otherwise specified with `mut`?*](https://stackoverflow.com/questions/29631590/why-is-immutability-enforced-in-rust-unless-otherwise-specified-with-mut) – ynn Apr 27 '20 at 21:37
  • 3
    Of course "const"antin would say that! Sorry, I was surprised no one else had said it... – Joshua Jurgensmeier Mar 24 '22 at 16:34
95

Extra Superfluous const are bad from an API stand-point:

Putting extra superfluous const's in your code for intrinsic type parameters passed by value clutters your API while making no meaningful promise to the caller or API user (it only hampers the implementation).

Too many 'const' in an API when not needed is like "crying wolf", eventually people will start ignoring 'const' because it's all over the place and means nothing most of the time.

The "reductio ad absurdum" argument to extra consts in API are good for these first two points would be is if more const parameters are good, then every argument that can have a const on it, SHOULD have a const on it. In fact, if it were truly that good, you'd want const to be the default for parameters and have a keyword like "mutable" only when you want to change the parameter.

So lets try putting in const whereever we can:

void mungerum(char * buffer, const char * mask, int count);

void mungerum(char * const buffer, const char * const mask, const int count);

Consider the line of code above. Not only is the declaration more cluttered and longer and harder to read but three of the four 'const' keywords can be safely ignored by the API user. However, the extra use of 'const' has made the second line potentially DANGEROUS!

Why?

A quick misread of the first parameter char * const buffer might make you think that it will not modify the memory in data buffer that is passed in -- however, this is not true! Superfluous 'const' can lead to dangerous and incorrect assumptions about your API when scanned or misread quickly.


Superfluous const are bad from a Code Implementation stand-point as well:

#if FLEXIBLE_IMPLEMENTATION
       #define SUPERFLUOUS_CONST
#else
       #define SUPERFLUOUS_CONST             const
#endif

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count);

If FLEXIBLE_IMPLEMENTATION is not true, then the API is “promising” not to implement the function the first way below.

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       // Will break if !FLEXIBLE_IMPLEMENTATION
       while(count--)
       {
              *dest++=*source++;
       }
}

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       for(int i=0;i<count;i++)
       {
              dest[i]=source[i];
       }
}

That’s a very silly promise to make. Why should you make a promise that gives no benefit at all to your caller and only limits your implementation?

Both of these are perfectly valid implementations of the same function though so all you’ve done is tied one hand behind your back unnecessarily.

Furthermore, it’s a very shallow promise that is easily (and legally circumvented).

inline void bytecopyWrapped(char * dest,
   const char *source, int count)
{
       while(count--)
       {
              *dest++=*source++;
       }
}
void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source,SUPERFLUOUS_CONST int count)
{
    bytecopyWrapped(dest, source, count);
}

Look, I implemented it that way anyhow even though I promised not to – just using a wrapper function. It’s like when the bad guy promises not to kill someone in a movie and orders his henchman to kill them instead.

Those superfluous const’s are worth no more than a promise from a movie bad-guy.


But the ability to lie gets even worse:

I have been enlightened that you can mismatch const in header (declaration) and code (definition) by using spurious const. The const-happy advocates claim this is a good thing since it lets you put const only in the definition.

// Example of const only in definition, not declaration
struct foo { void test(int *pi); };
void foo::test(int * const pi) { }

However, the converse is true... you can put a spurious const only in the declaration and ignore it in the definition. This only makes superfluous const in an API more of a terrible thing and a horrible lie - see this example:

struct foo
{
    void test(int * const pi);
};

void foo::test(int *pi) // Look, the const in the definition is so superfluous I can ignore it here
{
    pi++;  // I promised in my definition I wouldn't modify this
}

All the superfluous const actually does is make the implementer's code less readable by forcing him to use another local copy or a wrapper function when he wants to change the variable or pass the variable by non-const reference.

Look at this example. Which is more readable ? Is it obvious that the only reason for the extra variable in the second function is because some API designer threw in a superfluous const ?

struct llist
{
    llist * next;
};

void walkllist(llist *plist)
{
    llist *pnext;
    while(plist)
    {
        pnext=plist->next;
        walk(plist);
        plist=pnext;    // This line wouldn't compile if plist was const
    }
}

void walkllist(llist * SUPERFLUOUS_CONST plist)
{
    llist * pnotconst=plist;
    llist *pnext;
    while(pnotconst)
    {
        pnext=pnotconst->next;
        walk(pnotconst);
        pnotconst=pnext;
    }
}

Hopefully we've learned something here. Superfluous const is an API-cluttering eyesore, an annoying nag, a shallow and meaningless promise, an unnecessary hindrance, and occasionally leads to very dangerous mistakes.

Enlico
  • 23,259
  • 6
  • 48
  • 102
Adisak
  • 6,708
  • 38
  • 46
  • 11
    Why the downvotes? It's much more helpful if you leave a brief comment on a downvote. – Adisak Feb 22 '13 at 23:26
  • 9
    The whole point of using const argument is to make the marked line fail (plist = pnext). It is a reasonable safety measure to keep function argument immutable. I do agree with your point that they are bad in function declarations (since they are superflous), but they can serve their purposes in the implementation block. – touko Mar 04 '13 at 20:49
  • 2
    There is no reason to clutter your API to expose internal implementation details. Simple enough to make your implementation take parameters `T parm_foo` and assign immediately to a `const &T foo=parm_foo` and then use `foo` in the function -- you can enforce constantness of your parameters without unnecessary API clutter for your end users. – Adisak Mar 05 '13 at 00:39
  • 27
    @Adisak I don't see anything wrong with your answer, per se, but it seems from your comments that you are missing an important point. The function definition / implementation is **not** part of the API, which is only the function *declaration*. As you have said, declaring functions with const parameters is pointless and adds clutter. However users of the API may never need to see its implementation. Meanwhile the implementer may decided to const-qualify some of the parameters in the function definition ONLY for clarity, which is perfectly fine. – jw013 Aug 15 '13 at 19:17
  • @jw013 The language doesn't allow function implementations / definitions that differ from the declarations though. Therefore they *HAVE* to be the same. A "good" API should only expose that which actually makes a valid "contract" with the user and not be littered with superfluous nonsense that doesn't impact the API user. I weigh a good / clean API as better than some silly fake constraints on implementation that are easily circumvented. – Adisak Aug 20 '13 at 19:52
  • @Adisak I am not as familiar with the pedantic details of C++ as I am with C, but C99 definitely allows this (having const in the definition but not the prototype declaration). I've never disagreed with you that API clarity is paramount and should not be cluttered with implementation details. – jw013 Aug 20 '13 at 20:27
  • @jw013 C++ allows you to create functions with the same name and different signatures. It's called function overloading. It is implemented by the compiler decorating the actual C++ name based on the parameters which is applied functions that are not within an `extern "C" {}` (and all member functions of course). Depending on the types used, adding a spurious const may actually mean they are considered different functions and have different decorated names which would lead to linker errors. – Adisak Aug 21 '13 at 00:44
  • 19
    @jw013 is correct, `void foo(int)` and `void foo(const int)` are the exact same function, not overloads. ideone.com/npN4W4 ideone.com/tZav9R The const here is only an implementation detail of the function body, and has no effect on overload resolution. Leave const out of the declaration, for a safer and neater API, but put const in to the _definition_, if you intend not to modify the copied value. – Oktalist Feb 09 '14 at 00:07
  • Interesting @Oktalist. However, I'm not sure that I am terribly fond of the idea of having the definition not match declaration even if the it's allowed by the compiler. – Adisak Feb 12 '14 at 22:14
  • @Oktalist @jw013 OK, so you can mismatch const in declaration and definition. This only makes superfluous const more of a terrible thing and a horrible lie because you can ignore it in your definition - see this example: `class foo { void test(int * const pi); }; void foo::test(int *pi) { pi++; }` – Adisak Feb 13 '14 at 17:29
  • 4
    @Adisak I know this is old, but I believe the correct usage for a public API would be the other way around. That way developers working on the internals don't make mistakes such as `pi++` when they aren't supposed to. – RamblingMad Jul 15 '14 at 04:28
  • @CoffeeandCode I can see the occasional use for const in the function implementation if you choose to limit yourself from modifying a by-value variable in the implementation, but there is never a reason to have a spurious and unneccessay const in the header / public API definition. It's a lie because the implementation can ignore it. – Adisak Oct 07 '14 at 00:28
  • 1
    Don't get me wrong, const correctness is a wonderful thing that I value and recommend to all good programmers but the importance is the word "correctness". There is a difference between a 'correct' const (that actually relates an enforced API contract) and a 'bad' const (one that adds no value to the API contract and matters not to calling code whether it is present at all). – Adisak Oct 13 '15 at 18:46
  • 3
    "Too many 'const' in an API when not needed is like "crying wolf", eventually people will start ignoring 'const' because it's all over the place and means nothing most of the time" What? The point of const is that it can't be ignored, because the compiler won't let you ignore it. – Taywee Jun 16 '16 at 05:36
  • @Taywee - The compiler does let you ignore superfluous const in the declaration because your implementation / function definition can leave out the const (and I specifically show cases where the compiler will ignore this). There's a difference between necessary const and superfluous ones and I point them out in my answer. – Adisak Jul 18 '16 at 21:03
  • 3
    It sure helps catching subtle bugs that humans are prone to make, especially when const usage is consistent among code base. one eg. would be `std::string`'s `c_str()` function that returns a `const char *` for underlying string. Someone was mistakingly modifying the string being passed when it wasn't meant to. Compilers saved us. – Abhinav Gauniyal Sep 02 '16 at 17:06
  • Adding const to a pass-by-value parameter is polluting the API with implementation. It doesn't tell the caller anything and (as @Adisak says) clutters the API to make it harder to pick out the significant parts. We never allow pass-by-value function parameters to be modified within the body, and that is one key check in the code reviews (you do do code reviews?). If you want to change a value, take a copy (and you can give it a name that documents your usage). – Ian Brockbank Oct 07 '16 at 09:16
  • 2
    @AbhinavGauniyal using "const char *" for a string whose characters shouldn't be modified is smart. That's necessary const. However, an example of unnecessary const in an API would be using "const char * const" for the same string or even worse, using "char * const" for a string whose characters the function did modify. – Adisak Oct 07 '16 at 15:14
  • @IanBrockbank yeah code reviews are important for me, so important that there are two iterations, one by compiler and another by humans. The example I gave was the first one and it works out perfectly for me. – Abhinav Gauniyal Oct 07 '16 at 15:51
  • 4
    Downvoting because a large part of this answer seems to be a rant about something about which you were mistaken (const parameters in the function *definition* do not affect the API). Partway down you acknowledge this, but it would help if you would edit and either remove the initial wrong part, or add a big disclaimer at the beginning saying the first part is wrong. – Don Hatch Oct 13 '16 at 21:04
  • 1
    This answer is not useful. It's basically a long and verbose rant about something no one is doing or proposing to do. It's a classic straw man argument. – melpomene Feb 11 '17 at 22:37
  • @melpomene Maybe a rant but not a straw man -- the concept of extraneous const was proposed in the question and this directly addresses that question. Therefore your statement that no one is proposing to do this is simply false. And the anecdotal assumption that no one is doing this (because I've seen it in the wild) is logically speaking an argument from ignorance. – Adisak Feb 12 '17 at 23:47
  • 1
    @Adisak The question was about `const` on parameters in the function definition. The first three quarters of your answer are about `const` in the API, i.e. function declarations. There is a short aside about omitting `const` from the declaration, but then it goes off on a tangent and talks about omitting `const` from the definition only (WTF?). The last quarter is about how making a variable `const` means you can't modify it, and if you need to, you have to either remove the `const` or make a mutable copy. Cool story, but again unrelated to APIs or their designers. – melpomene Feb 13 '17 at 01:06
  • @melpomene I will agree that it is a wider, in depth observation of the wrongs of unnecessary const, precipitated by the proposed use of such in an API - and also that I have a holistic view that function implementations are influenced by choices in the API. I'm sorry that you are disturbed that my broader answer isn't more simple and narrow-minded to fit your liking. – Adisak Feb 13 '17 at 05:24
  • 1
    @Adisak No one proposed to use `const` in the API. Your "broader answer" simply doesn't address the question. – melpomene Feb 13 '17 at 08:19
  • @melpomene It's rare to have a primary criticism to an answer be that it covers the topic with too much depth but feel free to write your own answer with a much narrower scope if you believe that a more correct and succinct answer exist. I'll leave this one up because many other people have found it helpful. – Adisak Feb 13 '17 at 21:52
  • 1
    @Adisak For the fourth time, your answer doesn't cover "the topic"; it misses the topic entirely. I dislike how you keep trying to misrepresent my words. (It "covers" a completely different topic, but not very well or in depth; it's a lot of repetition and emotionally charged words (*clutter*, *movie bad guy*, *silly*, *lie*, *terrible thing*, *horrible lie*, *eyesore*, ...) but very shallow in technical content.) – melpomene Feb 13 '17 at 22:32
  • 1
    @melpomene Did you read the same text I did? You appear to seem to limit the following text to API's only where is seems to ask something much broader: *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? Personally I opt to use it extensively, including parameters, but in this case I wonder if it's worthwhile?* -- and my answer is use const as much as you should but not when it is unnecessary or misleading – Adisak Feb 14 '17 at 22:59
  • I saw too many misleading argument modification inside function scopes to beleive that the use of const argument is a must. – dom_beau Mar 27 '17 at 04:07
  • I feel like the macro section weakens your overall argument. If I use XYZ with macros and do terrible things, that's a macro problem, not an XYZ problem. I think you should take that part out. – Ryan Lundy Nov 06 '17 at 09:17
  • "Superfluous const" solution `#define CDa const* #define CP *const #define CPD const * const` * pointer to CONSTANT DATA * CONSTANT POINTER to data * CONSTANT pointer to CONSTANT data *** `void mungerum(char CP buffer, char CPD mask, CN int count);` vs `void mungerum(char * const buffer, const char * const mask, const int count);` Also solves the confusion of using const in front and after type and provides less verbosity. – slyy2048 Jul 27 '18 at 10:05
  • 1
    This is the best answer in my opinion, and the Google style guide also happens to agree with it in this case: https://google.github.io/styleguide/cppguide.html#Use_of_const: **"For a function parameter passed by value, const has no effect on the caller, thus is not recommended in function declarations. See [TotW #109](https://abseil.io/tips/109)."** – Gabriel Staples Mar 23 '20 at 23:06
  • I decided to add my own answer as well which adds my own words, supports @Adisak's, answer, and quotes the Google C++ Style Guide on the matter: https://stackoverflow.com/questions/117293/use-of-const-for-function-parameters/60823004#60823004. – Gabriel Staples Mar 23 '20 at 23:43
  • For the first part of your answer see https://stackoverflow.com/questions/1143262/what-is-the-difference-between-const-int-const-int-const-and-int-const to understand why implementation 1 fails but 2 can be compiled. But this is still an implementation issue and not an API issue. – Th. Thielemann May 28 '20 at 12:54
95

The following two lines are functionally equivalent:

int foo (int a);
int foo (const int a);

Obviously you won't be able to modify a in the body of foo if it's defined the second way, but there's no difference from the outside.

Where const really comes in handy is with reference or pointer parameters:

int foo (const BigStruct &a);
int foo (const BigStruct *a);

What this says is that foo can take a large parameter, perhaps a data structure that's gigabytes in size, without copying it. Also, it says to the caller, "Foo won't* change the contents of that parameter." Passing a const reference also allows the compiler to make certain performance decisions.

*: Unless it casts away the const-ness, but that's another post.

Ben Straub
  • 5,675
  • 3
  • 28
  • 43
  • 4
    That is not what this question is about; of course for referenced or pointed-to arguments it is a good idea to use const (if the referenced or pointed-to value is not modified). Note that it is not the *parameter* that is const in your pointer example; it is the thing the parameter points to that is. – tml May 05 '16 at 09:12
  • > Passing a const reference also allows the compiler to make certain performance decisions. classical fallacy - the compiler has to determine for itself the const-ness, the const keyword doesn't help with that thanks to pointer aliasing and const_cast – jheriko Oct 04 '16 at 16:54
38

const should have been the default in C++. Like this :

int i = 5 ; // i is a constant

var int i = 5 ; // i is a real variable
QBziZ
  • 3,170
  • 23
  • 24
  • 27
    Compatibility with C is too important, at least for the people that design C++, to even consider this. –  Mar 16 '10 at 04:57
  • 4
    Interesting, I had never thought of that. – Dan Sep 18 '12 at 20:56
  • 7
    Similarly, `unsigned` should have been the default in C++. Like this: `int i = 5; // i is unsigned` and `signed int i = 5; // i is signed`. – hkBattousai Jul 21 '15 at 13:49
  • @hkBattousai Why? const-by-default has a rationale, but I do not see it in unsigned-by-default. In fact, Bjarne thought size() returning unsigned type was a design error. In the initial design of span people wanted to make size() signed, but it was too late—incompatibility with size() of containers was not something most C++ standards committer members wanted. – Yongwei Wu Oct 28 '22 at 07:36
24

When I coded C++ for a living I consted everything I possibly could. Using const is a great way to help the compiler help you. For instance, const-ing your method return values can save you from typos such as:

foo() = 42

when you meant:

foo() == 42

If foo() is defined to return a non-const reference:

int& foo() { /* ... */ }

The compiler will happily let you assign a value to the anonymous temporary returned by the function call. Making it const:

const int& foo() { /* ... */ }

Eliminates this possibility.

Avdi
  • 18,340
  • 6
  • 53
  • 62
  • 7
    With what compiler did that work? GCC gives an error while trying to compile `foo() = 42`: error: lvalue required as left operand of assignment – gavrie Feb 09 '10 at 08:42
  • This is just incorrect. foo() = 42 is the same as 2 = 3, i.e. a compiler error. And returning a const is completely pointless. It doesn't do anything for a built-in type. – Josh Sep 19 '11 at 04:14
  • 2
    I've encountered this usage of const and I can tell you, in the end it produces way more hassle than benefits. Hint: `const int foo()` is of a different type than `int foo()`, which brings you into big trouble if you are using things like function pointers, signal/slot systems or boost::bind. – Mephane Sep 23 '11 at 11:32
  • 2
    I've corrected the code to include the reference return value. – Avdi Nov 28 '11 at 20:05
  • Isn't `const int& foo()` effectively the same as `int foo()`, due to return value optimization? – Zantier May 08 '14 at 11:20
18

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 param 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).
  4. 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.
  5. Never use top-level const [ie: const on variables passed by value] on values returned by a function.
  6. Using const on pointers or references returned by a function is up to the implementer, as it is sometimes useful.
  7. TODO: enforce some of the above with the following clang-tidy options:
  8. https://clang.llvm.org/extra/clang-tidy/checks/readability-avoid-const-params-in-decls.html
  9. 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]

Keywords: use of const in function parameters; coding standards; C and C++ coding standards; coding guidelines; best practices; code standards; const return values

Gabriel Staples
  • 36,492
  • 15
  • 194
  • 265
15

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.

Koedlt
  • 4,286
  • 8
  • 15
  • 33
Void - Othman
  • 3,441
  • 18
  • 18
  • 1
    Herb Sutter is a really smart guy :-) Definitely worth the read and I agree with ALL of his points. – Adisak Jun 14 '12 at 15:59
  • 2
    Well good article but I disagree with him about the arguments. I make them const as well because they are like variables, and I never want anyone making any changes to my arguments. – QBziZ Jul 03 '12 at 12:31
10

I use const on function parameters that are references (or pointers) which are only [in] data and will not be modified by the function. Meaning, when the purpose of using a reference is to avoid copying data and not to allow changing the passed parameter.

Putting const on the boolean b parameter in your example only puts a constraint on the implementation and doesn't contribute for the class's interface (although not changing parameters is usually advised).

The function signature for

void foo(int a);

and

void foo(const int a);

is the same, which explains your .c and .h

Asaf

Asaf R
  • 6,880
  • 9
  • 47
  • 69
9

I say const your value parameters.

Consider this buggy function:

bool isZero(int number)
{
  if (number = 0)  // whoops, should be number == 0
    return true;
  else
    return false;
}

If the number parameter was const, the compiler would stop and warn us of the bug.

6

If you use the ->* or .* operators, it's a must.

It prevents you from writing something like

void foo(Bar *p) { if (++p->*member > 0) { ... } }

which I almost did right now, and which probably doesn't do what you intend.

What I intended to say was

void foo(Bar *p) { if (++(p->*member) > 0) { ... } }

and if I had put a const in between Bar * and p, the compiler would have told me that.

Community
  • 1
  • 1
user541686
  • 205,094
  • 128
  • 528
  • 886
  • 6
    I would immediately be checking a reference on operator precedence when I'm about to mix together that many operators (if I don't already know 100%), so IMO it's a non-issue. – mk12 Aug 26 '12 at 02:15
  • 1
    I'd break that 1 difficult line up into about 5 or more crystal clear and easy-to-read lines, each with a descriptive variable name that makes that whole operation self-documenting. So, for me it's a non-issue. Condensing code into 1 line when readability suffers and errors creep in isn't a good idea, in my opinion. – Gabriel Staples Feb 26 '21 at 16:31
5

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.

Nemanja Trifunovic
  • 24,346
  • 3
  • 50
  • 88
5

const is pointless when the argument is passed by value since you will not be modifying the caller's object.

const should be preferred when passing by reference, unless the purpose of the function is to modify the passed value.

Finally, a function which does not modify current object (this) can, and probably should be declared const. An example is below:

int SomeClass::GetValue() const {return m_internalValue;}

This is a promise to not modify the object to which this call is applied. In other words, you can call:

const SomeClass* pSomeClass;
pSomeClass->GetValue();

If the function was not const, this would result in a compiler warning.

Dan Hewett
  • 2,200
  • 1
  • 14
  • 18
5

Marking value parameters 'const' is definitely a subjective thing.

However I actually prefer to mark value parameters const, just like in your example.

void func(const int n, const long l) { /* ... */ }

The value to me is in clearly indicating that the function parameter values are never changed by the function. They will have the same value at the beginning as at the end. For me, it is part of keeping to a very functional programming sort of style.

For a short function, it's arguably a waste of time/space to have the 'const' there, since it's usually pretty obvious that the arguments aren't modified by the function.

However for a larger function, its a form of implementation documentation, and it is enforced by the compiler.

I can be sure if I make some computation with 'n' and 'l', I can refactor/move that computation without fear of getting a different result because I missed a place where one or both is changed.

Since it is an implementation detail, you don't need to declare the value parameters const in the header, just like you don't need to declare the function parameters with the same names as the implementation uses.

Lloyd
  • 22,743
  • 2
  • 18
  • 7
4

I tend to use const wherever possible. (Or other appropriate keyword for the target language.) I do this purely because it allows the compiler to make extra optimizations that it would not be able to make otherwise. Since I have no idea what these optimizations may be, I always do it, even where it seems silly.

For all I know, the compiler might very well see a const value parameter, and say, "Hey, this function isn't modifying it anyway, so I can pass by reference and save some clock cycles." I don't think it ever would do such a thing, since it changes the function signature, but it makes the point. Maybe it does some different stack manipulation or something... The point is, I don't know, but I do know trying to be smarter than the compiler only leads to me being shamed.

C++ has some extra baggage, with the idea of const-correctness, so it becomes even more important.

jdmichal
  • 10,984
  • 4
  • 43
  • 42
  • While it might help in some cases, I suspect the possibility of promoting optimisations is dramatically overstated as a benefit of `const`. Rather, it is a matter of stating intent within the implementation and catching thinkoes later (accidentally incrementing the wrong local variable, because it wasn't `const`). In parallel, I'd also add that compilers are very welcome to change function signatures, in the sense that functions can be inlined, and once inlined the entire way they work can be changed; adding or removing references, making 'variables' literals, etc are all within the as-if rule – underscore_d Sep 23 '18 at 17:07
4

May be this wont be a valid argument. but if we increment the value of a const variable inside a function compiler will give us an error: "error: increment of read-only parameter". so that means we can use const key word as a way to prevent accidentally modifying our variables inside functions(which we are not supposed to/read-only). so if we accidentally did it at the compile time compiler will let us know that. this is specially important if you are not the only one who is working on this project.

HarshaXsoad
  • 776
  • 9
  • 30
2

In the case you mention, it doesn't affect callers of your API, which is why it's not commonly done (and isn't necessary in the header). It only affects the implementation of your function.

It's not particularly a bad thing to do, but the benefits aren't that great given that it doesn't affect your API, and it adds typing, so it's not usually done.

Luke Halliwell
  • 7,312
  • 6
  • 31
  • 31
2

I use const were I can. Const for parameters means that they should not change their value. This is especially valuable when passing by reference. const for function declares that the function should not change the classes members.

bpeterson76
  • 12,918
  • 5
  • 49
  • 82
Dror Helper
  • 30,292
  • 15
  • 80
  • 129
2

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".

Aurélien Gâteau
  • 4,010
  • 3
  • 25
  • 30
2

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.
YvesgereY
  • 3,778
  • 1
  • 20
  • 19
  • 2
    "What's good enough for the standard library is good for me" is not always true. For example, the standard library uses ugly variable names like `_Tmp` all the time - you don't want this (actually you're not allowed to use them). – anatolyg Jul 27 '17 at 07:44
  • 1
    @anatolyg this is an implementation detail – Fernando Pelliccioni Sep 20 '17 at 16:41
  • 2
    OK, both variable names and const-qualified types in argument lists are implementation details. What I want to say is, the implementation of the standard library is sometimes not good. Sometimes, you can (and should) do better. When was the code for the standard library written - 10 years ago? 5 years ago (some newest parts of it)? We can write better code today. – anatolyg Sep 23 '17 at 12:47
2

On compiler optimizations: http://www.gotw.ca/gotw/081.htm

sdcvvc
  • 25,343
  • 4
  • 66
  • 102
1

If the parameter is passed by value (and is not a reference), usually there is not much difference whether the parameter is declared as const or not (unless it contains a reference member -- not a problem for built-in types). If the parameter is a reference or pointer, it is usually better to protect the referenced/pointed-to memory, not the pointer itself (I think you cannot make the reference itself const, not that it matters much as you cannot change the referee). It seems a good idea to protect everything you can as const. You can omit it without fear of making a mistake if the parameters are just PODs (including built-in types) and there is no chance of them changing further along the road (e.g. in your example the bool parameter).

I didn't know about the .h/.cpp file declaration difference, but it does make some sense. At the machine code level, nothing is "const", so if you declare a function (in the .h) as non-const, the code is the same as if you declare it as const (optimizations aside). However, it helps you to enlist the compiler that you will not change the value of the variable inside the implementation of the function (.ccp). It might come handy in the case when you're inheriting from an interface that allows change, but you don't need to change to parameter to achieve the required functionality.

Attila
  • 28,265
  • 3
  • 46
  • 55
0

I wouldn't put const on parameters like that - everyone already knows that a boolean (as opposed to a boolean&) is constant, so adding it in will make people think "wait, what?" or even that you're passing the parameter by reference.

Khoth
  • 13,068
  • 3
  • 28
  • 27
  • 4
    sometimes you'd want to pass an object by reference (for performance reasons) but not change it, so const is mandatory then. Keeping all such parameters - even bools - const would then be good practise, making your code easier to read. – gbjbaanb Sep 22 '08 at 20:19
0

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.

gbjbaanb
  • 51,617
  • 12
  • 104
  • 148
  • I don't get this at all. *Why* would you be inclined to omit it in the cpp file (function definition)? That's where it actually means something and can catch errors. *Why* do you think it's best practice to put const in both places? In the header file (function declaration), it means nothing and clutters the API. Maybe there's some small value to having the decl and defn look exactly the same, but it seems to me that's a really minor benefit compared to the issue of cluttering the API. – Don Hatch Oct 13 '16 at 21:55
  • @DonHatch 8 years later, wow. Anyway, as the OP said "I was also surprised to learn that you can omit const from parameters in a function declaration but can include it in the function definition". – gbjbaanb Oct 14 '16 at 12:53
0

All the consts in your examples have no purpose. C++ is pass-by-value by default, so the function gets copies of those ints and booleans. Even if the function does modify them, the caller's copy is not affected.

So I'd avoid extra consts because

  • They're redudant
  • They clutter up the text
  • They prevent me from changing the passed in value in cases where it might be useful or efficient.
AShelly
  • 34,686
  • 15
  • 91
  • 152
  • 1
    `They prevent me from changing the passed in value in cases where it might be useful or efficient.` - but that's exactly why you might want to mark the argument as const in the function **definition** (not declaration!): to indicate that the argument (which is now a local variable) will not change. A non-const argument could indicate that your implementation is planning to change the local variable. – mercury0114 Feb 14 '23 at 17:10
0

As parameters are being passed by value,it doesnt make any difference if you specify const or not from the calling function's perspective.It basically does not make any sense to declare pass by value parameters as const.

-1

There's really no reason to make a value-parameter "const" as the function can only modify a copy of the variable anyway.

The reason to use "const" is if you're passing something bigger (e.g. a struct with lots of members) by reference, in which case it ensures that the function can't modify it; or rather, the compiler will complain if you try to modify it in the conventional way. It prevents it from being accidentally modified.

MarkR
  • 62,604
  • 14
  • 116
  • 151
-1

Const parameter is useful only when the parameter is passed by reference i.e., either reference or pointer. When compiler sees a const parameter, it make sure that the variable used in the parameter is not modified within the body of the function. Why would anyone want to make a by-value parameter as constant? :-)

  • For many reasons. Making a by-value parameter `const` states clearly: 'I do not need to modify this, so I am declaring that. If I try to modify it later, give me a compile-time error so that I can either fix my mistake or unmark as `const`.' So it's a matter of both code hygiene and safety. For all it takes to add to implementation files, it should be something people do as a pure reflex, IMO. – underscore_d Sep 23 '18 at 17:02
-1

I know the question is "a bit" outdated but as I came accross it somebody else may also do so in future... ...still I doubt the poor fellow will list down here to read my comment :)

It seems to me that we are still too confined to C-style way of thinking. In the OOP paradigma we play around with objects, not types. Const object may be conceptually different from a non-const object, specifically in the sense of logical-const (in contrast to bitwise-const). Thus even if const correctness of function params is (perhaps) an over-carefulness in case of PODs it is not so in case of objects. If a function works with a const object it should say so. Consider the following code snippet

#include <iostream>

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SharedBuffer {
private:

  int fakeData;

  int const & Get_(int i) const
  {

    std::cout << "Accessing buffer element" << std::endl;
    return fakeData;

  }

public:

  int & operator[](int i)
  {

    Unique();
    return const_cast<int &>(Get_(i));

  }

  int const & operator[](int i) const
  {

    return Get_(i);

  }

  void Unique()
  {

    std::cout << "Making buffer unique (expensive operation)" << std::endl;

  }

};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void NonConstF(SharedBuffer x)
{

  x[0] = 1;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ConstF(const SharedBuffer x)
{

  int q = x[0];

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main()
{

  SharedBuffer x;

  NonConstF(x);

  std::cout << std::endl;

  ConstF(x);

  return 0;

}

ps.: you may argue that (const) reference would be more appropriate here and gives you the same behaviour. Well, right. Just giving a different picture from what I could see elsewhere...

PavDub
  • 71
  • 4
-1

Being a VB.NET programmer that needs to use a C++ program with 50+ exposed functions, and a .h file that sporadically uses the const qualifier, it is difficult to know when to access a variable using ByRef or ByVal.

Of course the program tells you by generating an exception error on the line where you made the mistake, but then you need to guess which of the 2-10 parameters is wrong.

So now I have the distasteful task of trying to convince a developer that they should really define their variables (in the .h file) in a manner that allows an automated method of creating all of the VB.NET function definitions easily. They will then smugly say, "read the ... documentation."

I have written an awk script that parses a .h file, and creates all of the Declare Function commands, but without an indicator as to which variables are R/O vs R/W, it only does half the job.

EDIT:

At the encouragement of another user I am adding the following;

Here is an example of a (IMO) poorly formed .h entry;

typedef int (EE_STDCALL *Do_SomethingPtr)( int smfID, const char* cursor_name, const char* sql );

The resultant VB from my script;

    Declare Function Do_Something Lib "SomeOther.DLL" (ByRef smfID As Integer, ByVal cursor_name As String, ByVal sql As String) As Integer

Note the missing "const" on the first parameter. Without it, a program (or another developer) has no Idea the 1st parameter should be passed "ByVal." By adding the "const" it makes the .h file self documenting so that developers using other languages can easily write working code.

Paul Stearns
  • 856
  • 9
  • 30
  • @anatolyg, you are right it is a rant, but it does identify the problem with not properly using concepts within a language that may not be required, but provide for usability and self documentation. If you are writing code that requires other developers to use, it is important to make it usable. If someone would find it useful, I would be happy to post the AWK script, but it only works if the .h file is well formed. – Paul Stearns May 28 '17 at 19:50
  • To illustrate your point, you should better post a bad `*.h` example and a good one. And also the translated file, and show where the script had problems, and how the problems disappear if you use `const` in the proper place. – anatolyg May 29 '17 at 08:21
  • @anatolyg, Is that better? – Paul Stearns May 29 '17 at 11:45
  • At least now I understand what you are trying to say! But I disagree: both `int smfID` and `const int smfID` mean "pass by value" in C++, while `int& smfID` means "pass by reference". – anatolyg May 29 '17 at 13:42
  • @anatolyg The .h file has no "&" in it, and those parameters seem to be used interchangeably for ByRef/ByVal. The only way I find out is to either search through the .CHM file documentation, or wait until my program blows up with a "System.AccessViolationException" error and try to figure out which parameter it is. The particular dll I am currently using has ~100 public methods, and I would like to automate the creation of the "Declare Functions." – Paul Stearns May 29 '17 at 14:45