const and non-const versions of *static* member functions - c++

I have two versions of the same static member function: one takes a pointer-to-const parameter and that takes a pointer-to-non-const parameter. I want to avoid code duplication.
After reading some stack overflow questions (these were all about non-static member functions though) I came up with this:
class C {
private:
static const type* func(const type* x) {
//long code
}
static type* func(type* x) {
return const_cast<type*>(func(static_cast<const type*>(x)));
}
public:
//some code that uses these functions
};
(I know juggling with pointers is generally a bad idea, but I'm implementing a data structure.)
I found some code in libstdc++ that looks like this:
NOTE: these are not member functions
static type* local_func(type* x)
{
//long code
}
type* func(type* x)
{
return local_func(x);
}
const type* func(const type* x)
{
return local_func(const_cast<type*>(x));
}
In the first approach the code is in a function that takes a pointer-to-const parameter.
In the second approach the code is in a function that takes a pointer-to-non-const parameter.
Which approach should generally be used? Are both correct?

The most important rule is that an interface function (public method, a free function other than one in a detail namespace, etc), should not cast away the constness of its input. Scott Meyer was one of the first to talk about preventing duplication using const_cast, here's a typical example (How do I remove code duplication between similar const and non-const member functions?):
struct C {
const char & get() const {
return c;
}
char & get() {
return const_cast<char &>(static_cast<const C &>(*this).get());
}
char c;
};
This refers to instance methods rather than static/free functions, but the principle is the same. You notice that the non-const version adds const to call the other method (for an instance method, the this pointer is the input). It then casts away constness at the end; this is safe because it knows the original input was not const.
Implementing this the other way around would be extremely dangerous. If you cast away constness of a function parameter you receive, you are taking a big risk in UB if the object passed to you is actually const. Namely, if you call any methods that actually mutate the object (which is very easy to do by accident now that you've cast away constness), you can easily get UB:
C++ standard, section § 5.2.11/7 [const cast]
[ Note: Depending on the type of the object, a write operation through the pointer, lvalue or pointer to data member resulting from a
const_cast that casts away a const-qualifier may produce undefined
behavior. —end note ]
It's not as bad in private methods/implementation functions because perhaps you carefully control how/when its called, but why do it this way? It's more dangerous to no benefit.
Conceptually, it's often the case that when you have a const and non-const version of the same function, you are just passing along internal references of the object (vector::operator[] is a canonical example), and not actually mutating anything, which means that it will be safe either way you write it. But it's still more dangerous to cast away the constness of the input; although you might be unlikely to mess it up yourself, imagine a team setting where you write it the wrong way around and it works fine, and then someone changes the implementation to mutate something, giving you UB.
In summary, in many cases it may not make a practical difference, but there is a correct way to do it that's strictly better than the alternative: add constness to the input, and remove constness from the output.

I have actually only ever seen your first version before, so from my experience it is the more common idiom.
The first version seems correct to me while the second version can result in undefined behavior if (A) you pass an actual const object to the function and (B) the long code writes to that object. Given that in the first case the compiler will tell you if you're trying to write to the object I would never recommend option 2 as it is. You could consider a standalone function that takes/returns const however.

Related

Why we use const array in a function, even the original array are not const? [duplicate]

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

Why member function parameter const mismatch allowed? [duplicate]

From the C++ Primer 5th Edition, it says:
int f(int){ /* can write to parameter */}
int f(const int){ /* cannot write to parameter */}
The two functions are indistinguishable. But as you know, the two functions really differ in how they can update their parameters.
Can someone explains to me?
EDIT
I think I didn't interpret my question well. What I really care is why C++ doesn't allow these two functions simultaneously as different function since they are really different as to "whether parameter can be written or not". Intuitively, it should be!
EDIT
The nature of pass by value is actually pass by copying argument values to parameter values. Even for references and pointers where thee copied values are addresses. From the caller's viewpoint, whether const or non-const is passed to the function does not influence values (and of course types of) copied to parameters.
The distinction between top-level const and low-level const matters when copying objects. More specifically, top-level const(not the case of low-level const) is ignored when copying objects since copying won't influence the copied object. It is immaterial whether the object copied to or copied from is const or not.
So for the caller, differentiating them is not necessary. Likely, from the function viewpoint, the top-level const parameters doesn't influence the interface and/or the functionality of function. The two function actually accomplish the same thing. Why bother implementing two copies?
allow these two functions simultaneously as different function since they are really different as to "whether parameter can be written or not". Intuitively, it should be!
Overloading of functions is based on the parameters the caller provides. Here, it's true that the caller may provide a const or non-const value but logically it should make no difference to the functionality that the called function provides. Consider:
f(3);
int x = 1 + 2;
f(x);
If f() does different thing in each of these situations, it would be very confusing! The programmer of this code calling f() can have a reasonable expectation of identical behaviour, freely adding or removing variables that pass parameters without it invalidating the program. This safe, sane behaviour is the point of departure that you'd want to justify exceptions to, and indeed there is one - behaviours can be varied when the function's overloaded ala:
void f(const int&) { ... }
void f(int&) { ... }
So, I guess this is what you find non-intuitive: that C++ provides more "safety" (enforced consistent behaviour through supporting only a single implementation) for non-references than references.
The reasons I can think of are:
So when a programmer knows a non-const& parameter will have a longer lifetime, they can select an optimal implementation. For example, in the code below it may be faster to return a reference to a T member within F, but if F is a temporary (which it might be if the compiler matches const F&) then a by-value return is needed. This is still pretty dangerous as the caller has to be aware that the returned reference is only valid as long as the parameter's around.
T f(const F&);
T& f(F&); // return type could be by const& if more appropriate
propagation of qualifiers like const-ness through function calls as in:
const T& f(const F&);
T& f(F&);
Here, some (presumably F member-) variable of type T is being exposed as const or non-const based on the const-ness of the parameter when f() is called. This type of interface might be chosen when wishing to extend a class with non-member functions (to keep the class minimalist, or when writing templates/algos usable on many classes), but the idea is similar to const member functions like vector::operator[](), where you want v[0] = 3 allowed on a non-const vector but not a const one.
When values are accepted by value they go out of scope as the function returns, so there's no valid scenario involving returning a reference to part of the parameter and wanting to propagate its qualifiers.
Hacking the behaviour you want
Given the rules for references, you can use them to get the kind of behaviour you want - you just need to be careful not to modify the by-non-const-reference parameter accidentally, so might want to adopt a practice like the following for the non-const parameters:
T f(F& x_ref)
{
F x = x_ref; // or const F is you won't modify it
...use x for safety...
}
Recompilation implications
Quite apart from the question of why the language forbids overloading based on the const-ness of a by-value parameter, there's the question of why it doesn't insist on consistency of const-ness in the declaration and definition.
For f(const int) / f(int)... if you are declaring a function in a header file, then it's best NOT to include the const qualifier even if the later definition in an implementation file will have it. This is because during maintenance the programmer may wish to remove the qualifier... removing it from the header may trigger a pointless recompilation of client code, so it's better not to insist they be kept in sync - and indeed that's why the compiler doesn't produce an error if they differ. If you just add or remove const in the function definition, then it's close to the implementation where the reader of the code might care about the constness when analysing the function behaviour. If you have it const in both header and implementation file, then the programmer wishes to make it non-const and forgets or decides not to update the header in order to avoid client recompilation, then it's more dangerous than the other way around as it's possible the programmer will have the const version from the header in mind when trying to analyse the current implementation code leading to wrong reasoning about the function behaviour. This is all a very subtle maintainence issue - only really relevant to commercial programming - but that's the basis of the guideline not to use const in the interface. Further, it's more concise to omit it from the interface, which is nicer for client programmers reading over your API.
Since there is no difference to the caller, and no clear way to distinguish between a call to a function with a top level const parameter and one without, the language rules ignore top level consts. This means that these two
void foo(const int);
void foo(int);
are treated as the same declaration. If you were to provide two implementations, you would get a multiple definition error.
There is a difference in a function definition with top level const. In one, you can modify your copy of the parameter. In the other, you can't. You can see it as an implementation detail. To the caller, there is no difference.
// declarations
void foo(int);
void bar(int);
// definitions
void foo(int n)
{
n++;
std::cout << n << std::endl;
}
void bar(const int n)
{
n++; // ERROR!
std::cout << n << std::endl;
}
This is analogous to the following:
void foo()
{
int = 42;
n++;
std::cout << n << std::endl;
}
void bar()
{
const int n = 42;
n++; // ERROR!
std::cout << n << std::endl;
}
In "The C++ Programming Language", fourth edition, Bjarne Stroustrup writes (§12.1.3):
Unfortunately, to preserve C compatibility, a const is ignored at the highest level of an argument type. For example, this is two declarations of the same function:
void f(int);
void f(const int);
So, it seems that, contrarily to some of the other answers, this rule of C++ was not chosen because of the indistinguishability of the two functions, or other similar rationales, but instead as a less-than-optimal solution, for the sake of compatibility.
Indeed, in the D programming language, it is possible to have those two overloads. Yet, contrarily to what other answers to this question might suggest, the non-const overload is preferred if the function is called with a literal:
void f(int);
void f(const int);
f(42); // calls void f(int);
Of course, you should provide equivalent semantics for your overloads, but that is not specific to this overloading scenario, with nearly indistinguishable overloading functions.
As the comments say, inside the first function the parameter could be changed, if it had been named. It is a copy of the callee's int. Inside the second function, any changes to the parameter, which is still a copy of the callee's int, will result in a compile error. Const is a promise you won't change the variable.
A function is useful only from the caller's perspective.
Since there is no difference to the caller, there is no difference, for these two functions.
I think the indistinguishable is used in the terms of overloading and compiler, not in terms if they can be distinguished by caller.
Compiler does not distinguish between those two functions, their names are mangled in the same way. That leads to situation when compiler treats those two declarations as redefinition.
Answering this part of your question:
What I really care is why C++ doesn't allow these two functions simultaneously as different function since they are really different as to "whether parameter can be written or not". Intuitively, it should be!
If you think about it a little more, it isn't at all intinuitive - in fact, it doesn't make much sense. As everybody else has said, a caller is in no way influenced when a functon takes it's parameter by value and it doesn't care, either.
Now, let's suppose for a moment that overload resolution worked on top level const, too. Two declarations like this
int foo(const int);
int foo(int);
would declare two different functions. One of the problems would be which functions would this expression call: foo(42). The language rules could say that literals are const and that the const "overload" would be called in this case. But that's the least of a problem.
A programmer feeling sufficiently evil could write this:
int foo(const int i) { return i*i; }
int foo(int i) { return i*2; }
Now you'd have two overloads that are appear semanticaly equivalent to the caller but do completely different things. Now that would be bad. We'd be able to write interfaces that limit the user by the way they do things, not by what they offer.

C++: Why is const_cast evil?

I keep hearing this statement, while I can't really find the reason why const_cast is evil.
In the following example:
template <typename T>
void OscillatorToFieldTransformer<T>::setOscillator(const SysOscillatorBase<T> &src)
{
oscillatorSrc = const_cast<SysOscillatorBase<T>*>(&src);
}
I'm using a reference, and by using const, I'm protecting my reference from being changed. On the other hand, if I don't use const_cast, the code won't compile. Why would const_cast be bad here?
The same applies to the following example:
template <typename T>
void SysSystemBase<T>::addOscillator(const SysOscillatorBase<T> &src)
{
bool alreadyThere = 0;
for(unsigned long i = 0; i < oscillators.size(); i++)
{
if(&src == oscillators[i])
{
alreadyThere = 1;
break;
}
}
if(!alreadyThere)
{
oscillators.push_back(const_cast<SysOscillatorBase<T>*>(&src));
}
}
Please provide me some examples, in which I can see how it's a bad idea/unprofessional to use a const_cast.
Thank you for any efforts :)
Because you're thwarting the purpose of const, which is to keep you from modifying the argument. So if you cast away the constness of something, it's pointless and bloating your code, and it lets you break promises that you made to the user of the function that you won't modify the argument.
In addition, using const_cast can cause undefined behaviour. Consider this code:
SysOscillatorBase<int> src;
const SysOscillatorBase<int> src2;
...
aFieldTransformer.setOscillator(src);
aFieldTransformer.setOscillator(src2);
In the first call, all is well. You can cast away the constness of an object that is not really const and modify it fine. However, in the second call, in setOscillator you are casting away the constness of a truly const object. If you ever happen to modify that object in there anywhere, you are causing undefined behaviour by modifying an object that really is const. Since you can't tell whether an object marked const is really const where it was declared, you should just never use const_cast unless you are sure you'll never ever mutate the object ever. And if you won't, what's the point?
In your example code, you're storing a non-const pointer to an object that might be const, which indicates you intend to mutate the object (else why not just store a pointer to const?). That might cause undefined behaviour.
Also, doing it that way lets people pass a temporary to your function:
blah.setOscillator(SysOscillatorBase<int>()); // compiles
And then you're storing a pointer to a temporary which will be invalid when the function returns1. You don't have this problem if you take a non-const reference.
On the other hand, if I don't use const_cast, the code won't compile.
Then change your code, don't add a cast to make it work. The compiler is not compiling it for a reason. Now that you know the reasons, you can make your vector hold pointers to const instead of casting a square hole into a round one to fit your peg.
So, all around, it would be better to just have your method accept a non-const reference instead, and using const_cast is almost never a good idea.
1 Actually when the expression in which the function was called ends.
by using const, I'm protecting my reference from being changed
References can't be changed, once initialized they always refer to the same object. A reference being const means the object it refers to cannot be changed. But const_cast undoes that assertion and allows the object to be changed after all.
On the other hand, if I don't use const_cast, the code won't compile.
This isn't a justification for anything. C++ refuses to compile code that may allow a const object to be changed because that is the meaning of const. Such a program would be incorrect. const_cast is a means of compiling incorrect programs — that is the problem.
For example, in your program, it looks like you have an object
std::vector< SysOscillatorBase<T> * > oscillators
Consider this:
Oscillator o; // Create this object and obtain ownership
addOscillator( o ); // cannot modify o because argument is const
// ... other code ...
oscillators.back()->setFrequency( 3000 ); // woops, changed someone else's osc.
Passing an object by const reference means not only that the called function can't change it, but that the function can't pass it to someone else who can change it. const_cast violates that.
The strength of C++ is that it provides tools to guarantee things about ownership and value semantics. When you disable those tools to make the program compile, it enables bugs. No good programmer finds that acceptable.
As a solution to this particular problem, it looks likely that the vector (or whatever container you're using) should store the objects by value, not pointer. Then addOscillator can accept a const reference and yet the stored objects are modifiable. Furthermore, the container then owns the objects and ensures they are safely deleted, with no work on your part.
The use of const_cast for any reason other than adapting to (old) libraries where the interfaces have non-const pointers/references but the implementations don't modify the arguments is wrong and dangerous.
The reason that it is wrong is because when your interface takes a reference or pointer to a constant object you are promising not to change the object. Other code might depend on you not modifying the object. Consider for example, a type that holds an expensive to copy member, and that together with that it holds some other invariants.
Consider a vector<double> and a precomputed average value, the *average is updated whenever a new element is added through the class interface as it is cheap to update then, and if it is requested often there is no need to recompute it from the data every time. Because the vector is expensive to copy, but read access might be needed the type could offer a cheap accessor that returns a std::vector<double> const & for user code to check values already in the container. Now, if user code casts away the const-ness of the reference and updates the vector, the invariant that the class holds the average is broken and the behavior of your program becomes incorrect.
It is also dangerous because you have no guarantee that the object that you are passed is actually modifiable or not. Consider a simple function that takes a C null terminated string and converts that to uppercase, simple enough:
void upper_case( char * p ) {
while (*p) {
*p = ::to_upper(*p);
++p;
}
}
Now lets assume that you decide to change the interface to take a const char*, and the implementation to remove the const. User code that worked with the older version will also work with the new version, but some code that would be flagged as an error in the old version will not be detected at compile time now. Consider that someone decided to do something as stupid as upper_case( typeid(int).name() ). Now the problem is that the result of typeid is not just a constant reference to a modifiable object, but rather a reference to a constant object. The compiler is free to store the type_info object in a read-only segment and the loader to load it in a read-only page of memory. Attempting to change it will crash your program.
Note that in both cases, you cannot know from the context of the const_cast whether extra invariants are maintained (case 1) or even if the object is actually constant (case 2).
On the opposite end, the reason for const_cast to exist was adapting to old C code that did not support the const keyword. For some time functions like strlen would take a char*, even though it is known and documented that the function will not modify the object. In that case it is safe to use const_cast to adapt the type, not to change the const-ness. Note that C has support for const for a very long time already, and const_cast has lesser proper uses.
The const_cast would be bad because it allows you to break the contract specified by the method, i.e. "I shall not modify src". The caller expects the method to stick to that.
It's at least problematic. You have to distinguish two constnesses:
constness of the instantiated variable
This may result in physical constness, the data being placed in a read-only segment
constness of the reference parameter / pointer
This is a logical constness, only enforced by the compiler
You are allowed to cast away the const only if it's not physically const, and you can't determine that from the parameter.
In addition, it's a "smell" that some parts of your code are const-correct, and others aren't. This is sometimes unavoidable.
In your first example, you assign a const reference to what I assume is a non-const pointer. This would allow you to modify the original object, which requires at least a const cast. To illustrate:
SysOscillatorBase<int> a;
const SysOscillatorBase<int> b;
obj.setOscillator(a); // ok, a --> const a --> casting away the const
obj.setOscilaltor(b); // NOT OK: casting away the const-ness of a const instance
Same applies to your second example.
, while I can't really find the reason why const_cast is evil.
It is not, when used responsibily and when you know what you're doing. (Or do you seriously copy-paste code for all those methods that differ only by their const modifier?)
However, the problem with const_cast is that it can trigger undefined behavior if you use it on variable that originally was const. I.e. if you declare const variable, then const_cast it and attempt to modify it. And undefined behavior is not a good thing.
Your example contains precisely this situation: possibly const variable converted into non-const. To avoid the problem store either const SysOscillatorBase<T>*(const pointer) or SysOscillatorBase<T> (copy) in your object list, or pass reference instead of const reference.
You are violating a coding contract. Marking a value as const is saying you can use this value but never change it. const_cast breaks this promise and can create unexpected behaviour .
In the examples you give, it seems your code is not quite right. oscillatorSrc should probably be a const pointer, although if you really do need to change the value then you should not pass it in as a const at all.
Basicly const promises you and the compiler that you will not change the value. The only time you should use when you use a C library function (where const didn't exist), that is known not to change the value.
bool compareThatShouldntChangeValue(const int* a, const int* b){
int * c = const_cast<int*>(a);
*c = 7;
return a == b;
}
int main(){
if(compareThatShouldntChangeValue(1, 7)){
doSomething();
}
}
You probably need to define you container as containing const objects
template <typename T> struct Foo {
typedef std::vector<SysOscillator<T> const *> ossilator_vector;
}
Foo::ossilator_vector<int> oscillators;
// This will compile
SysOscillator<int> const * x = new SysOscillator<int>();
oscillators.push_back(x);
// This will not
SysOscillator<int> * x = new SysOscillator<int>();
oscillators.push_back(x);
That being said if you have no control over the typedef for the container maybe it
is ok to const_cast at the interface between your code and the library.

When to use const and const reference in function args?

When writing a C++ function which has args that are being passed to it, from my understanding const should always be used if you can guarantuee that the object will not be changed or a const pointer if the pointer won't be changed.
When else is this practice advised?
When would you use a const reference and what are the advantages over just passing it through a pointer for example?
What about this void MyObject::Somefunc(const std::string& mystring) What would be the point in having a const string if a string is in fact already an immutable object?
Asking whether to add const is the wrong question, unfortunately.
Compare non-const ref to passing a non-const pointer
void modifies(T &param);
void modifies(T *param);
This case is mostly about style: do you want the call to look like call(obj) or call(&obj)? However, there are two points where the difference matters. If you want to be able to pass null, you must use a pointer. And if you're overloading operators, you cannot use a pointer instead.
Compare const ref to by value
void doesnt_modify(T const &param);
void doesnt_modify(T param);
This is the interesting case. The rule of thumb is "cheap to copy" types are passed by value — these are generally small types (but not always) — while others are passed by const ref. However, if you need to make a copy within your function regardless, you should pass by value. (Yes, this exposes a bit of implementation detail. C'est le C++.)
Compare const pointer to non-modifying plus overload
void optional(T const *param=0);
// vs
void optional();
void optional(T const &param); // or optional(T param)
This is related to the non-modifying case above, except passing the parameter is optional. There's the least difference here between all three situations, so choose whichever makes your life easiest. Of course, the default value for the non-const pointer is up to you.
Const by value is an implementation detail
void f(T);
void f(T const);
These declarations are actually the exact same function! When passing by value, const is purely an implementation detail. Try it out:
void f(int);
void f(int const) {/*implements above function, not an overload*/}
typedef void C(int const);
typedef void NC(int);
NC *nc = &f; // nc is a function pointer
C *c = nc; // C and NC are identical types
The general rule is, use const whenever possible, and only omit it if necessary. const may enable the compiler to optimize and helps your peers understand how your code is intended to be used (and the compiler will catch possible misuse).
As for your example, strings are not immutable in C++. If you hand a non-const reference to a string to a function, the function may modify it. C++ does not have the concept of immutability built into the language, you can only emulate it using encapsulation and const (which will never be bullet-proof though).
After thinking #Eamons comment and reading some stuff, I agree that optimization is not the main reason for using const. The main reason is to have correct code.
The questions are based on some incorrect assumptions, so not really meaningful.
std::string does not model immutable string values. It models mutable values.
There is no such thing as a "const reference". There are references to const objects. The distinction is subtle but important.
Top-level const for a function argument is only meaningful for a function implementation, not for a pure declaration (where it's disregarded by the compiler). It doesn't tell the caller anything. It's only a restriction on the implementation. E.g. int const is pretty much meaningless as argument type in a pure declaration of a function. However, the const in std::string const& is not top level.
Passing by reference to const avoids inefficient copying of data. In general, for an argument passing data into a function, you pass small items (such as an int) by value, and potentially larger items by reference to const. In the machine code the reference to const may be optimized away or it may be implemented as a pointer. E.g., in 32-bit Windows an int is 4 bytes and a pointer is 4 bytes. So argument type int const& would not reduce data copying but could, with a simple-minded compiler, introduce an extra indirection, which means a slight inefficiency -- hence the small/large distinction.
Cheers & hth.,
The main advantage of const reference over const pointer is following: its clear that the parameter is required and cannot be NULL.
Vice versa, if i see a const pointer, i immedeately assume the reason for it not being a reference is that the parameter could be NULL.

Use of 'const' for function parameters

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