30

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?

jww
  • 97,681
  • 90
  • 411
  • 885
Tony The Lion
  • 61,704
  • 67
  • 242
  • 415
  • 1
    possible duplicate of [How to pass objects to functions in C++?](http://stackoverflow.com/questions/2139224/how-to-pass-objects-to-functions-in-c) – sbi Oct 19 '10 at 10:08
  • 2
    Reason 1: String is not immutable. Reason 2: to be able to pass string literals or c-strings or rvalues. If you took by plain reference, no conversions would apply, nor could you pass a temporary object as argument – Armen Tsirunyan Oct 19 '10 at 11:17

4 Answers4

48

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
  • If you want to pass NULL and still use a reference, look into the [Null Object Pattern](http://en.wikipedia.org/wiki/Null_Object_pattern). – Björn Pollex Oct 19 '10 at 18:38
  • `void test(int i)` is not `void test(int const i)` because the later does not allow to change value i – Duke Feb 09 '15 at 13:17
7

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.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
  • 3
    I don't think the compiler can actually optimize anything at all based on a const annotation - const does not imply immutability, merely the lack of intent to change within this scope. – Eamon Nerbonne Oct 19 '10 at 10:06
  • +1 for the reminder that strings aren't immutable - that's critically important! – Eamon Nerbonne Oct 19 '10 at 10:06
  • @Eamon: [Read this](http://stackoverflow.com/questions/212237) for some pros and cons on optimization from `const`. – Björn Pollex Oct 19 '10 at 10:14
3

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

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • 1
    People often use the term "const reference" meaning "references to const objets"... I'd say the former - given it has no other possible meaning or interpretation - is an informal way to discuss the later, rather than that there's a subtle distinction between something that doesn't exist and something that does ;-). – Tony Delroy Oct 19 '10 at 10:23
  • 1
    You can have a `const` reference to a non-`const` object. The `const`-ness (that even a word?) is a property of the reference, not the object. – Björn Pollex Oct 19 '10 at 10:23
  • 2
    @Tony: the problem of accurate terminology here is very real. "const pointer" is very different from "pointer to const" (even if some Microsoft programmers don't grok that). And with MSVC 'T& const' (a "const reference") causes the compiler to exclaim "anachronism used : qualifiers on reference are ignored", so while it's evidently unthinkable to some, at one time it was evidently accepted by this compiler -- and so it's IMO very much relevant to make the distinction. Cheers, – Cheers and hth. - Alf Oct 19 '10 at 10:31
  • @Space_C0wb0y: I'm sorry but in modern C++ what you write is literally meaningless. So I'm not sure what you're trying to say. EDIT: perhaps you're trying to say that the object referred to by a reference to const T, doesn't need to be originally const (or that there can be aliased references permitting modification)? – Cheers and hth. - Alf Oct 19 '10 at 10:33
  • 1
    @Alf: Suppose you have a function that take a reference to a `const` object as parameter. Now you call that function with a non-`const` object as argument. Does it make the object `const`? No. The reference makes it appear as `const` in the function, but the object itself is not `const`. I am no expert on C++ standards and definitions, I just find your terminology a bit misleading. – Björn Pollex Oct 19 '10 at 10:36
  • @Alf: A quick find in http://www2.research.att.com/~bs/bs_faq2.html turns up `const reference`... maybe someone should tell him ;-). re Space_COwbOy: `int x; const int& rx = x;`. So, "reference to a const object" may be as confusing as "const reference", depending on your perspective. – Tony Delroy Oct 19 '10 at 10:38
  • @Tony: a quick search in The C++ Programming Language 2nd. ed also turns up `void main`. Everybody makes mistakes. And it's contextual: what matters about we say things to a beginner, who doesn't have a good understanding already in place, is different from what we might say to an expert (when that expert knows that you know what you're talking about, so can "adjust" the meaning). Cheers, – Cheers and hth. - Alf Oct 19 '10 at 10:46
  • @Space_C0wb0y In C++, all references are "const" as you cannot move a reference from one object to another. They may only have const-access to the objects they refer to, which means you may only call const-declared methods using them, and if they have member variables that you have access to, you may only call const methods on those too and cannot assign them. Note that constness does not propagate. So for example if my class has a pImpl (pointer to implementation), my const methods can actually call non-const methods on my pImpl. – CashCow Oct 19 '10 at 10:53
  • @CashCow. "[references] may only have const-access to the objects they refer to"... not true. You can have do e.g. `int a; int& b = a; b = 5;`. – Tony Delroy Oct 19 '10 at 11:38
  • 1
    @Alf: very true, but ultimately I'll just say point-blank that I think you're projecting your own perspective on this rather than representing any concensus or best-practice of the expert C++ community - more of how you'd like them to use the term rather than how they do - but if you tell me that impressions off base then I'll accept it... I don't buy every new C++ book that comes out, hang out on comp.lang.c++.moderated etc. these days, attend conferences etc.. – Tony Delroy Oct 19 '10 at 11:42
  • Playing with semantics for "const reference" is more harmful than helpful. (I used to do it too, for other terms, before I started explicitly using less standardese.) Let's just explain that "const reference" means reference to a const object and skip the confusion. –  Oct 19 '10 at 13:17
  • Not only is an int const parameter in a function forward declaration "pretty much meaningless", it's entirely unnecessary: the two function signatures (int) and (int const) are identical. You can even later add that const when defining: `void f(int); void f(int const) {}`. –  Oct 19 '10 at 13:19
  • @Roger Pate: re "identical" at the language level, yes, as I wrote in the answer it's "disregarded by the compiler". But it's not "entirely unnecessary". In previous discussions about this people have cited tools (MS?) that are not comfortable with adding `const` for a formal argument type in a function definition; you lose some functionality. Cheers & hth., – Cheers and hth. - Alf Oct 19 '10 at 23:28
  • @Tony: re whose perspective, I think that's just argumentative. Take a look at the [C++ FAQ](http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.1), note how it's employing as precise terminology as possible for this. I'm not going into a discussion about who are regarded as experts or what terminology they employ in what contexts; I'm certain one can disagree or pretend to disagree about who are experts etc. till kingdom come... – Cheers and hth. - Alf Oct 19 '10 at 23:34
  • 1
    @Alf: I'm not trying to be argumentative - it's not a worthwhile thing to sustain argument about, but given you cite the C++ FAQ, will quickly mention it supports both being in common use: Q 18.11 speaks of non-`const` reference twice and `const` reference once, though supporting your position: 18.7 confusingly explains `X& const` a nonsensical, redundantly "`const` reference", and carefully uses clearer terms in the introductory 18.1. – Tony Delroy Oct 20 '10 at 01:09
1

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.

Adesit
  • 159
  • 5