C++: Const Reference, Before VS After Type-Specifier

C++: const reference, before vs after type-specifier

No difference as const is read right-to-left with respect to the &, so both represent a reference to an immutable Fred instance.

Fred& const would mean the reference itself is immutable, which is redundant; when dealing with const pointers both Fred const* and Fred* const are valid but different.

It's a matter of style, but I prefer using const as a suffix since it can be applied consistently including const member functions.

Const before or const after?

why is there two correct ways of specifying const data and in what situation would you prefer or need one over the other if any?

Essentially, the reason that the position of const within specifiers prior to an asterisk does not matter is that the C grammar was defined that way by Kernighan and Ritchie.

The reason they defined the grammar in this way was likely that their C compiler parsed input from left-to-right and finished processing each token as it consumed that. Consuming the * token changes the state of the current declaration to a pointer type. Encountering const after * means the const qualifier is applied to a pointer declaration; encountering it prior to the * means the qualifier is applied to the data pointed to.

Because the semantic meaning does not change if the const qualifier appears before or after the type specifiers, it is accepted either way.

A similar sort of case arises when declaring function pointers, where:

  • void * function1(void) declares a function which returns void *,

  • void (* function2)(void) declares a function pointer to a function which returns void.

Again the thing to notice is that the language syntax supports a left-to-right parser.

Const before or after the type?

Cv-qualifiers like const apply to whatever is to the left of them, unless there is nothing, in which case they apply to the right. For string const&, the const applies to the string to its left. For const string&, the const applies to the string to its right. That is, they're both references to const string, so in this case, it makes no difference.

Some people prefer to have it on the left (like const int) because it reads from left to right. Some people prefer to have it on the right (like int const) to avoid using the special-case (int const * const is more consistent than const int* const, for example).

Why does putting const on the left side of an ampersand valid when referring to a pointer but not on the right?

What does the ampersand actually doing here?

It is a punctuator that that designates a reference type. It is similar to how the asterisk designates a pointer type.

Why is putting const on the left of it valid but not on the right

Because const qualifier applies to whatever is on the left side of it1. And if const is to the right of the ampersand, then the qualifier would apply to the reference. But that is not allowed by the language. Const cannot be applied to a reference (unlike it can be applied to a pointer). Such qualification would be meaningless. References cannot be modified regardless.

There is no such thing as const reference in C++. Although colloquially, it is common to use "const reference" when people actually mean reference to const.


1 Except when the qualifier is the left most token in which case it applies to the right const T& is same as T const &. All of this applies to volatile as well.

Can a function take an argument by const reference *without* accepting temporaries as an argument?

Assuming const doesn't interfere with how you use the object, and you never need to rebind what object is being observed, and the observed Foo instance is guaranteed to outlive its observer(s), then a reference will work.

If you delete the constructor taking an rvalue-reference to a Foo, you will prevent the accidental lifetime extension you mentioned:

class ObservesFoo
{
Foo const& p_foo;

ObservesFoo(Foo const& t_foo) : p_foo(t_foo) { }
ObservesFoo(Foo&& t_foo) = delete;
};

What is the difference between a const reference and normal parameter?

The difference is more prominent when you are passing a big struct/class:

struct MyData {
int a,b,c,d,e,f,g,h;
long array[1234];
};
void DoWork(MyData md);
void DoWork(const MyData& md);

When you use use 'normal' parameter, you pass the parameter by value and hence creating a copy of the parameter you pass. If you are using const reference, you pass it by reference and the original data is not copied.

In both cases, the original data cannot be modified from inside the function.


EDIT:

In certain cases, the original data might be able to get modified as pointed out by Charles Bailey in his answer.



Related Topics



Leave a reply



Submit