views:

131

answers:

4

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?

+3  A: 

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.

Space_C0wb0y
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
+1 for the reminder that strings aren't immutable - that's critically important!
Eamon Nerbonne
@Eamon: [Read this](http://stackoverflow.com/questions/212237) for some pros and cons on optimization from `const`.
Space_C0wb0y
A: 

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
+1  A: 

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

Alf P. Steinbach
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
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.
Space_C0wb0y
Alf P. Steinbach
@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)?
Alf P. Steinbach
@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.
Space_C0wb0y
@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`. So, "reference to a const object" may be as confusing as "const reference", depending on your perspective.
Tony
@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,
Alf P. Steinbach
@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
@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 = 5;`.
Tony
@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
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.
Roger Pate
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) {}`.
Roger Pate
Alf P. Steinbach
@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...
Alf P. Steinbach
Tony
+2  A: 

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
Roger Pate
Thanks for the detailed answer!! :)
Tony
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).
Space_C0wb0y
A C++ pointer *is* the null object pattern.
Roger Pate