Asking whether to add const is the wrong question, unfortunately.
void modifies(T ¶m);
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.
void doesnt_modify(T const ¶m);
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++.)
void optional(T const *param=0);
// vs
void optional();
void optional(T const ¶m); // 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.
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.,
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With