As stated in book Effective C++: \"Use const whenever possible.\", one would assume that this definition: Vec3f operator+(Vec3f &other);
would be b
C++ FAQ:
If you find ordinary type safety helps you get systems correct (it does; especially in large systems), you'll find const correctness helps also.
You should use const
when you want to be sure not to change variable accidentally or intentionally. Some constants (globals and class static, strings & integers, but not variables with nontrivial constructor) can be placed in read-only parts of the executable, therefore result in segmentation fault if you try to write to it.
You should be explicit using const
as a specifier on functions that follow this principle as well as on function arguments. If you don't have to change actual argument, make it const
. This doesn't limit the possible usages of such function, but extends them, because now they might be used on const
arguments, and on const
objects.
In declaration
const int* foo(const int* const&) const;
every const
means something different and yes, obviously it should be used if it is needed.
Using const
increases type-safety of your program.
C++ FAQ:
[18.3] Should I try to get things const correct "sooner" or "later"?
At the very, very, very beginning.
When using const
you are telling the compiler something.
It can then use that information to check that you are not doing something that you should not be doing and also enables it to optimize the code.
So when using const
it enables it to be smarter.
I think that using const
whenever possible is a good way to go. It adds implicit documentation to your code and increases type safety, as noted by the other answers.
It's nice to know that you can call const
functions without having to worry about whether they change an object's internal state and that passing const
pointers or references to something other object will keep it safe from encapsulation breakage. It also lets objects owning const
references get the most value out of whatever that reference is pointing to.
Also, applying const
from the get-go is a good idea because it can be a pain to add later. For example, if you have a class:
class A
{
public:
//...
int getCount()
{
return m_count;
}
private:
int m_count;
}
And another:
class B
{
public:
//...
int getInternalCount()
{
return m_a->getCount();
}
private:
A* m_a;
}
And you want to do:
void foo( const B* b )
{
int count = b->getInternalCount();
//-- Do something
}
This is a perfectly valid use case, but you then have to go and add const
to multiple places to support it (B::getInternalCount()
and A::getCount()
). If you do it from the very start, it's actually quite easy to use const
and it makes the design much more obvious to other developers. If you're working on your own, it still helps a lot, but it's not as much of a concern. When working in a team, though, I found it really helped when we started enforcing const
and retrofitted some of our legacy code to adhere to it more.
Long story short: I recommend always using it.
Using const
whereever possible is generally a good thing, but it's a bad wording. You should be using const
whereever it is possible and makes sense.
Above all else (it may, rarely, open extra optimization opportunities) it is a means to document your intention of not modifying something.
In the concrete example of a member operator+
that you have given, the best solution would not be to make everything const
, but a freestanding operator+
which bases on member operator+=
and takes one argument by value like so:
T operator+(T one, T const& two) const { return one += two; }
This solution works with T
appearing on either side of the plus sign, it allows for chaining, it doesn't replicate code, and it allows the compiler to perform the maximum of optimizations.
The semantics of operator+
require that a copy be made, so you can as well have the compiler make it (the other one will be optimized out).
It would be possible to make one
a const&
, but then you would have to manually make a copy, which would likely be sub-optimal (and much less intellegible).
The original purpose of const
is to deal with problems, which arise when you use magic numbers and hard-coded values in general.
A bit stupid, but picturesque example to show the point. Such code is error-prone and inconvenient.
c1 = 3.14159 * diameter1;
c2 = 3.14159 * diameter2;
You'd rather be better defining Pi as a constant.
const double PI = 3.14159;
c1 = PI * diameter1;
c2 = PI * diameter2;
Compared to variables constants have "priviliges". In your example it makes sense to pass other vector by const reference, because thanks to this function will accept temporary (rvalue) as its parameter.
Vec3f operator+(const Vec3f &other) const;
// Would not be possible with Vec3f operator+(Vec3f &other) const;
Vec3f v = u + Vec3f(1, 0, 0);
With constexpr
you can use constants in contexts such as for example static array allocation
constexpr std::size_t LENGTH = 10;
int arr[LENGTH];
So it's not to prevent you from accidentally setting some random value (you would have to be exceptionally stupid programmer to make such mistakes). It does not make sense to use it whenever possible, but only when you want to specify a constant.
This is not the first time I see weird statements from "Effective C++".