Use Const Wherever Possible in C++

Use const wherever possible in C++?

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.

Summary

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.

Should I use the 'const' keyword in c++

Yes, you should make all variables const if you are never going to change its value after initialization. This prevents bugs where you accidentally change a value you're not supposed to. You seem to be aware of this already.

In addition, there is something that you might not be aware of, which is that making an int variable const also makes it a constant-expression, so long as the initializer itself is also a constant-expression, e.g. the int literal 56. This allows you to use it in contexts where you need a constant-expression, e.g. as the dimension of a static array:

const int size = 56;
int a[size]; // ok
int size = 56;
int a[size]; // error

What's the correct way to use const in C++?

Where you use const depends on the purpose of the function. As James suggests in his comment (which is worth putting as an answer), put const anywhere you can:

If the function is intended to modify state within it's object instance, don't put const at the end of the signature.

If the function is intended to modify one of it's reference or pointer parameters, don't put const on the parameter.

If the variable referenced by a pointer or reference should be modified, don't put const on the type (remember, const applies to the part of the definition immediately prior).

If the returned reference/pointer references a variables that should not be changed by the received, do put const on the type.

Answering the examples given in the question is impossible without knowing the purpose of the functions. My tendency would be to use string ToString() const and char* ToString() const, with very clear documentation on who is responsible for deleteing the char*.


As an extra note, const char* and char const* are identical (pointer to unmodifiable characters). char* const, on the other hand, is an unmodifiable pointer to modifiable characters.

C++ const keyword - use liberally?

This, IMHO, is overusing.
When you say 'const int age,...' what you actually say is "you can't change even the local copy inside your function". What you do is actually make the programmer code less readable by forcing him to use another local copy when he wants to change age/pass it by non-const reference.

Any programmer should be familiar with the difference between pass by reference and pass by value just as any programmer should understand 'const'.

Why should I not use `const` in this simple function?

From the caller's perspective, both the first and the second form are the same.

Since the integers are passed by value, even if the function modifies a and b, the modified values are copies of the original and won't be visible to the caller.

However, from the function implementer's perspective there's a difference. In fact, in the second form:

int add(const int a, const int b)

you will get a compiler error if you try to modify the values of a and b inside the function's body, as they are marked as const.

Instead, you can change those values if you omit the const.

Again, those modifications will not be visible to the caller.

When to use const and const reference in function args?

Asking whether to add const is the wrong question, unfortunately.

Compare non-const ref to passing a non-const pointer

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.

Compare const ref to by value

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

Compare const pointer to non-modifying plus overload

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.

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

When, if ever, should we use const?

I believe the only time "const" is appropriate is when there is a spec that you're coding against that is more durable than the program you're writing. For instance, if you're implementing the HTTP protocol, having a const member for "GET" is appropriate because that will never change, and clients can certainly hard-code that into their compiled apps without worrying that you'll need to change the value later.

If there's any chance at all you need to change the value in future versions, don't use const.

Oh! And never assume const is faster than a readonly field unless you've measured it. There are JIT optimizations that may make it so it's actually exactly the same.

Passing const reference parameters whenever possible

Why didn't they make char c a const reference parameter?

char is so small, it's generally cheaper to pass it by value rather than by reference (const or otherwise).



Related Topics



Leave a reply



Submit