Related
I am starting to come to grips with const in terms of a reference parameter. The way I see it is that a constant reference parameter basically sets the parameter in question to the original memory space that calls the function into question. And since it is const, the value in itself cannot change.
I have found a solution with regards to a code that delivers matrix multiplication A=BC:
vector<vector<double> > mult(const vector<vector<double> >& B, const vector<vector<double> >& C)
{ ...;
return A;
}
int main()
{
vector<vector<double> > B, C;
cout << mult(B,C) << endl;
return 0;
}
I agree with the structure of the code but I am confused about the neccessity of "const" and "&". Surely the code would be exactly the same if I excluded both from the above? For "&" one could perhaps that we use less memory space by not creating an extra space for the parameters of "mult". But the use of const seems unnecessary to me.
The '&' prevents the copy constructor from being called, i.e., prevents a duplicate copy being made. It is more efficient this way because you avoid the constructor on the invocation and the destructor on the exit.
The 'const' keyword communicates to the caller that the object to which the reference refers will not be changed in the function. It also allows the function to be called with constant vectors as input. In other words, if B and C are constant, you couldn't call mult() without the const keyword in the signature.
It's been a while in C++ for me, but I think that's the gist. I'm certainly open to corrections on my answer.
There are only a few times when a const reference is, strictly-speaking, necessary. The most common is when you need to pass a const object by reference. The type system will prevent this unless the function promises not to modify the object. It can also make a difference when a function is overloaded to do something different when the object is const, and you specifically want the const version. (The latter is probably bad design!)
It would alternatively be possible to remove the const qualifier from the function argument, and to give any overloaded functions different names. In fact, references in C++ are syntactic sugar for C-style pointers, and it would be possible to replace void foo (T& x) with void foo(T* x) and every occurrence of x inside foo with (*x). Adding const T& or T* const simply means that the program will not be able to modify the object through that reference or pointer.
C had no const keyword until 1989, and you could do all the same things without it, but it’s present in order to help developers avoid bugs related to modifying the wrong variable.
It is not really necessary. As long as you pass in non-const parameters to your function, the program will not behave differently.
I can state a few examples in your case:
If one of the parameters you have to pass is const, it will not work.
Furthermore, you won't be able to do something like mult({{1, 2}, {3, 4}}, b); because that temporary object can only implicitly convert into a const reference.
If you put the definition and declaration in separate translation units (i.e. .cpp files) then the compiler might miss some optimization potential, because it wouldn't be able to assume that mult() doesn't modify its parameters.
Another argument is simply that const shows your intents more clearly.
See a few more reasons on isocpp.
The reference & prevents an unnecessary copy. Your parameter type is a std::vector, which means that copying will involve memory allocations, and for performance reasons you do not want that.
On a side note, if your code is meant to manipulate matrices, then a std::vector of std::vector is very inappropriate for performance reasons, as it makes it extremely cache inefficient and causes unnecessary dynamic allocations. You would rather use a 1D std::array and wrap it to handle 2D indices nicely. std::array has sizes known as compile time, which means that every function you pass a specific std::array to knows its size on compile-time which is good for performance, especially as std::array makes it possible to avoid dynamic allocation.
int sum(const int a,int b)
{
b=10;
// a=5; error
return (a+b);
}
in above example a is const and not b.
So a as read-only variable. If you try to change the value of a you get error. That means you have to use value of a which pass when function is call.
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.
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).
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.
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 :)
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.
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.
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
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.
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.
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):
For pass-by-value there is no benefit to adding const. All it does is:
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.
and adding const unnecessarily clutters the code with consts everywhere, drawing attention away from the consts that are truly necessary to have safe code.
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!".
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]
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.
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:
"Google C++ Style Guide" "Use of const" section
"Tip of the Week #109: Meaningful const in Function Declarations"
Adisak's Stack Overflow answer on "Use of 'const' for function parameters"
"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).
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.
Never use top-level const [ie: const on variables passed by value] on values returned by a function.
Using const on pointers or references returned by a function is up to the implementer, as it is sometimes useful.
TODO: enforce some of the above with the following clang-tidy options:
https://clang.llvm.org/extra/clang-tidy/checks/readability-avoid-const-params-in-decls.html
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
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
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.
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.
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.
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.
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.
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.
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.
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.
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".
On compiler optimizations: http://www.gotw.ca/gotw/081.htm
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.
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.
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.
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.
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.
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.
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.
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.
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? :-)
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...
In the code review process, one of my coworkers mentioned to me that "const"s in front of "primitive types" used as a function parameter in a header is meaningless, and he recommended to remove these "const"s. He suggested using "const" only in the source file in such cases. Primitive types mean types such as "int", "char", "float", etc.
The following is example.
example.h
int ProcessScore(const int score);
example.cc
int ProcessScore(const int score) {
// Do some calculation using score
return some_value;
}
His suggestion is doing as follows:
example.h
int ProcessScore(int score); // const is removed here.
example.cc
int ProcessScore(const int score) {
// Do some calculation using score
return some_value;
}
But I'm somewhat confused. Usually, the user will look at only the header, so if there is inconsistency between the header and the source file, it might cause confusion.
Could anyone give some advice on this?
For all types (not just primitives), the top level const qualifiers in the function declaration are ignored. So the following four all declare the same function:
void foo(int const i, int const j);
void foo(int i, int const j);
void foo(int const i, int j);
void foo(int i, int j);
The const qualifier isn't ignored inside the function body, however. There it can have impact on const correctness. But that is an implementation detail of the function. So the general consensus is this:
Leave the const out of the declaration. It's just clutter, and doesn't affect how clients will call the function.
Leave the const in the definition if you wish for the compiler to catch any accidental modification of the parameter.
Function parameter declared const and without const is the same when coming to overload resolution. So for example functions
void f(int);
void f(const int);
are the same and could not be defined together. As a result it is better not to use const in declaration for parameters at all to avoid possible duplications. (I'm not talking about const reference or const pointer - since const modifier is not top level.)
Here is exact quote from the standard.
After producing the list
of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the
function type. The resulting list of transformed parameter types and the presence or absence of the ellipsis
or a function parameter pack is the function’s parameter-type-list. [ Note: This transformation does not
affect the types of the parameters. For example, int(*)(const int p, decltype(p)*) and int(*)(int, const int*) are identical types. — end note ]
Usefulness of const in the function definition is debatable - reasoning behind it is the same as using const for declaring local variable - it demonstrates to other programmers reading the code the this value is not going to be modified inside the function.
Follow the recommendations given you in code review.
Using const for value arguments has no semantic value — it is only meaningful (potentially) for implementation of your function — and even in that case I would argue that it is unnecessary.
edit:
Just to be clear: your function’s prototype is the public interface to your function. What const does is offer a guarantee that you will not modify references.
int a = 7;
do_something( a );
void do_something( int& x ); // 'a' may be modified
void do_something( const int& x ); // I will not modify 'a'
void do_something( int x ); // no one cares what happens to x
Using const is something akin to TMI — it is unimportant anywhere except inside the function whether or not 'x' is modified.
edit2: I also very much like the information in StoryTeller’s answer
As many other people have answered, from an API perspective, the following are all equivalent, and are equal for overload-resolution:
void foo( int );
void foo( const int );
But a better question is whether or not this provides any semantic meaning to a consumer of this API, or whether it provides any enforcement of good behaviours from a developer of the implementation.
Without any well-defined developer coding guidelines that expressly define this, const scalar arguments have no readily obvious semantic meaning.
From a consumer:
const int does not change your input. It can still be a literal, or it can be from another variable (both const or non-const)
From a developer:
const int imposes a restriction on a local copy of a variable (in this case, a function argument). This just means to modify the argument, you take another copy of the variable and modify it instead.
When calling a function that accepts an argument by-value, a copy is made of that argument on the stack for the called function. This gives the function a local copy of the argument for its entire scope that can then be modified, used for calculations, etc -- without affecting the original input passed into the call. Effectively, this provides a local variable argument of its input.
By marking the argument as const, it simply means that this copy cannot be modified; but it does not prohibit the developer from copying it and making modifications to this copy. Since this was a copy from the start, it does not enforce all that much from inside the implementation -- and ultimately doesn't make much difference from the consumer's perspective.
This is in contrast to passing by reference, wherein a reference to int& is semantically different from const int&. The former is capable of mutating its input; the latter is only capable of observing the input (provided the implementation doesn't const_cast the const-ness away -- but lets ignore this possibility); thus, const-ness on references have an implied semantic meaning.
It does not provide much benefit being in the public API; and (imo) introduces unnecessary restrictions into the implementation. As an arbitrary, contrived example -- a simple function like:
void do_n_times( int n )
{
while( n-- > 0 ) {
// do something n times
}
}
would now have to be written using an unnecessary copy:
void do_n_times( const int n )
{
auto n_copy = n;
while( n_copy-- > 0 ) {
// do something n times
}
}
Regardless of whether const scalars are used in the public API, one key thing is to be consistent with the design. If the API randomly switches between using const scalar arguments to using non-const scalars, then it can cause confusion as to whether there is meant to be any implied meaning to the consumer.
TL;DR: const scalar types in a public API don't convey semantic meaning unless explicitly defined by your own guidelines for your domain.
I thought that const is a hint for the compiler that some expressions don't change and to optimize accordingly. For example I was testing if a number is prime by looking for divisors up to the square root of the number and I thought that declaring the argument const would take the sqrt(n) outside of the for loop, but it didn't.
It may not be necessary in the header, but then again, you could say that all you need is to not modify the argument and it is never necessary. I'd rather see const where it is const, not just in the source, but in the header too. Inconsistencies between declaration and definition make me circumspect. Just my opinion.
Note: I am using the g++ compiler (which is I hear is pretty good and supposed to be pretty close to the standard).
Not trying to start a grammar war, but just a random question... What is the ideal way to declare a pointer?
int* pI = 4;
int *pI = 4;
(or my favorite, I know it's non-pretty, but I like it):
int*pI = 4;
Same question stands for references:
int& rI = 4;
int &rI = 4;
or
int&rI = 4;
Maybe there is no right answer. Similarly, should I care whether a constant integer is declared as:
const int I = 4;
or
int const I = 4;
I'm fine with not caring...
I do like the way a const function is declared by having a const after the last parenthesis.
And I believe a constant function has a distinct function signature than the similar non-const function (i.e. the const-nesss is part of the function signature, unlike most sources that say it just depends on the arguments type and the return type).
Is this right? Should I care?
I prefer
int* a;
int& b;
for the following reason: the type is int* and not int. For me - the type belongs together and needs to stand separate from the name. I know this introduces some problems with
int* a, b;
but that's why I don't declare to variables in one line.
Other than that - like VJo said: stick to the coding standard. If everyone around you does it one way, don't do it the other.
Coding standards might tell you how to declare or define your variables.
Other then that, use whatever suits you better.
And I believe a constant function has a distinct function signature than the similar non-const function (i.e. the const-nesss is part of the function signature, unlike most sources that say it just depends on the arguments type and the return type).
A constant function has a keyword const which is appended at the end of it.
int doSomething() const;
It means that the function will not alter the state(members) of the class.
Mentioning const on an argument implies that the function will not alter the state of that variable(param in below example) being passed to the function.
int doSomething(const int param);
Mentioning const before the return type applies to the type being returned by the function.
const int doSomething();
Implies the function returns a const integer value.
So yes your understanding is correct. And there is no other way to declare a function const except putting a const after the last paranthesis.
Also, note that const member function can be only called on a const object, while a non const member function can be called by const as well as non const objects of that class.
As far as the way of declaring, Each organization have their own coding guidelines and you should stick to that, Yes there is no distinct advantage of using those contructs you mentioned in either way with respect to compiler optimization or treatment. Just follow what you like or what your organzation wants you to follow.
Bjarne Stroustrup uses:
int* a;
so, that's good enough for me.
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.
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).
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.
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 :)
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.
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.
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
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.
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.
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):
For pass-by-value there is no benefit to adding const. All it does is:
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.
and adding const unnecessarily clutters the code with consts everywhere, drawing attention away from the consts that are truly necessary to have safe code.
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!".
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]
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.
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:
"Google C++ Style Guide" "Use of const" section
"Tip of the Week #109: Meaningful const in Function Declarations"
Adisak's Stack Overflow answer on "Use of 'const' for function parameters"
"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).
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.
Never use top-level const [ie: const on variables passed by value] on values returned by a function.
Using const on pointers or references returned by a function is up to the implementer, as it is sometimes useful.
TODO: enforce some of the above with the following clang-tidy options:
https://clang.llvm.org/extra/clang-tidy/checks/readability-avoid-const-params-in-decls.html
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
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
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.
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.
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.
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.
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.
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.
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.
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.
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".
On compiler optimizations: http://www.gotw.ca/gotw/081.htm
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.
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.
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.
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.
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.
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.
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.
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.
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? :-)
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...