I have seen const used twice in the declaration of a static array before and now that I am creating my own static array I am wondering why const would be needed twice in some situations.
Does having an array of pointers make a difference?
a. static const TYPE name[5];
b. static const TYPE const name[5];
c. static const TYPE* name[5];
d. static const TYPE* const name[5];
My understanding is that b. is invalid, but if using const twice is valid, what is its purpose?
const TYPE* x;
Means that the thing that x points at is const.
TYPE* const x;
Means that the pointer x is const.
Combining the 2 you get:
const TYPE* const x;
Meaning the pointer and the thing pointed to are both const.
You can apply any cv-qualifier (const or volatile) to any type, including cv-qualified types -- yet not in the same declaration. However, they bind more strongly than any operator, in terms of precedence and can be applied on both sides of the qualified type:
// Let T by any type:
T const tr;
const T tl;
const T const tlr; // only in C
const const const const const T t5; // only in C
typedef const T CT;
CT const tcc; // fine, although CT was already const
declare exactly the same, a constant T. If T already has cv-qualifiers, this doesn't change the meaning of additional qualification.
Now, to the precedence; You can say "I want a pointer to a constant T":
const T (* tp);
which is usually written as
const T* tp;
because the const binds stronger than the * anyway. In the same pattern, you can define a variable that is "constant but points at a mutable T":
T (* const tp) = 0; // must be initialised, because tp is immutable
which is commonly written as
T* const tp = 0;
In the same vein the subscript operator [] is applied -- with the same precedence as in expressions.
In the first code block you have a redundant duplicate const in the second line, which has no effect. (In fact, good compilers will warn you about this.) You're declaring an array of 5 const TYPEs, that's it.
The second code block has two different scenarios: The first line makes an array of five mutable pointers to const TYPEs, while the latter makes an array of five constant pointers to const TYPEs.
Note that you must initialize an array of constants: Since you can't change the values later, it doesn't make sense to define them uninitialized.
Using const twice on a type is illegal in C++ 2003 but legal in C++ 2011 (see 7.1.6.1 [decl.type.cv] paragraph 1: "Redundant cv-qualifications are ignored."). When you used
static const TYPE const name[5];
you made TYPE constant twice. Note, however, that this declaration is illegal in C++ 2011, too, because you need initialize a const object when declaring it. The meaning of
const TYPE
and
TYPE const
is absolutely equivalent: In both cases you make the TYPE object constant. For consistency, I always put the const to the right because every except for the top-level type the const has to be put on the right side (well, unless some coding guideline mandates differently but I'm fighting silly coding guidelines).
When using pointers, thinks become different. There are two types involved: type pointed to type and the pointer. Each one of these can be made const separately:
TYPE const* ptr1(0); // non-const pointer to const TYPE
TYPE* const ptr2(0); // const pointer to non-const TYPE
TYPE const* const ptr3(0); // const pointer to const TYPE
The best way to figure out what is made const is to read the type declaration from right to left. Of course, this assumes to that const qualifiers are put into the right location. You can replace const by volatile or const volatile in the discussion above and the same reasoning applies.
Related
I am studying C++ templates, and I got stuck thinking about the interaction between const and types that are arguments to template functions. Specifically, I am thinking about how consts interact with template types when applied outside of the template parameter list.
I have tried looking for this interaction in C++ Primer 5th ed (Lippman) and in the C++11 standard draft, but const in this context is either not explicitly mentioned or (in the case of the standard) rather complex in its description (I'm still somewhat new to C++).
Here is a code example of my problem:
template<typename T>
const T & constify(T & t) {
return t;
}
...
int* i = 0x12345678;
constify(i);
I have two different expectations of the return type:
The deduced return type is const (int *) &, i.e the const is applied afterwards, so that we cannot modify the int pointer but we can modify what it points to.
The deduced return type is const int * &, i.e all declarators and qualifiers are applied all at once instead of as in 1. Here, we can no longer modify the int pointed to by the integer, but we can modify the pointer itself.
For me, the first one makes more sense because it has a natural "substitution-like" rule behind it, similar to typedef. But my question is; which of these (if any) is correct and why?
Template type substitutions are not textual, so do not think of them in terms of the textual type definition.
In your example, T is deduced to be int * - let's call it intptr. You are making const reference to it, so return value becomes const intptr&. That means, that the pointer itself can't be modified through this reference, but the value it points to can be modified.
Last, but not the least, you could have easily verifed your assumptions before asking the question :)
The 1st one is correct, and the return type would be int * const &, i.e. the reference to const pointer to non-const int; not const int * &, i.e. the reference to non-const pointer to const int.
const is qualified on T itself, when T is a pointer const T would be a const pointer but not a pointer to const pointee.
const consistent location is on the right of the type. Some declarations, like variables, also allow putting const on the left, but others, like member function definitions, only allow const on the right.
If you always put/apply const on the right it helps you to think about it in the right way. This is the reason many boost libraries put const on the right.
constify apples const on the right, hence, it turns T that is int* into int* const - a constant pointer to non-constant int. And apply the reference on the right of that: int* const&.
I would like to return a pointer to an array owned by a class. However, I do not want to allow users to modify that data or pointer. According to how I understand things you need return a constant pointer to constant data using the following syntax.
const Type *const Class::Method() {
return this->data_;
}
However gcc gives the following warning when compiling.
warning: type qualifiers ignored on function return type
Why is this warning provided by gcc? What does it mean? If this is not the right syntax for what I want, what is?
The warning you get is because the final const is overlooked. Take it off and you're set.
You don't need to return a const pointer to const data, just a pointer to const data (which is const Type*). Just as it doesn't make sense to return a const int, it doesn't make sense to return a T* const, because as soon as the value is assigned to a new variable, that const is discarded.
The top level const is ignored for built-in types. As there is a rule in C++[3.14p4]: class and array prvalues can have cv-qualified types; other prvalues always have cv-unqualified types.. In your case const Type* const, the top level const making the pointer const is ignored.
You could add const to the end: const Type * Class::Method() const {...}. This would prevent the pointer from being modified inside the member function. However, since the member function returns prvalue which is non-modifiable, it is not necessary to do this to prevent modification of the pointer member outside of the class (and this is also the reason why this rule exists in C++). It may be useful when you want to call the function with a constant reference to a Class object, etc., but for what you are doing, this doesn't seem necessary.
First const is right, the second const does not make any sense. Just look at this example:
const int foo();
int a = foo();
The fact if foo returns const int or just int does not change anything in this case. Same for Type *.
I'm struggling to get my head around the differences between the various places you can put 'const' on a function declaration in c++.
What is the difference between const at the beginning:
const int MyClass::showName(string id){
...
}
And const at the end like:
int MyClass::showName(string id) const{
...
}
Also, what is the result of having const both at the beginning and at the end like this:
const int MyClass::showName(string id) const{
...
}
const int MyClass::showName(string id) returns a const int object. So the calling code can not change the returned int. If the calling code is like const int a = m.showName("id"); a = 10; then it will be marked as a compiler error. However, as noted by #David Heffernan below, since the integer is returned by copy the calling code is not obliged to use const int. It can very well declare int as the return type and modify it. Since the object is returned by copy, it doesn't make much sense to declare the return type as const int.
int MyClass::showName(string id) const tells that the method showName is a const member function. A const member function is the one which does not modify any member variables of the class (unless they are marked as mutable). So if you have member variable int m_a in class MyClass and if you try to do m_a = 10; inside showName you will get a compiler error.
Third is the combination of the above two cases.
The const attached to the return value applies to the return value. Since the return value is copied it's a pointless declaration and it makes no difference whether or not you include it.
The const after the parameter list means that the function does not modify any state of the object that is not marked as mutable. This is a const member function and if you have a const object the compiler will not allow you to call non-const member functions on a const object.
There is no interaction between these two uses of const - they are completely independent constructs
The difference is that the const applies to different things.
This says that showName returns a constant int value -- one that is immutable. Of course since the int is returned by value the presence of const here does not play any role.
const int MyClass::showName(string id)
And this says that showName does not modify the observable state of MyClass (technically: it does not modify any member that is not declared mutable), and therefore you are allowed to call it on a value of type const MyClass.
int MyClass::showName(string id) const
If you use both consts then both of the above apply.
Questions like this tend to strengthen my resolve to follow the advice of Dan Saks as outlined in this "Conversations with a Guru" article: http://www.drdobbs.com/conversationsa-midsummer-nights-madness/184403835 .
In particular it deals with how the placement of const changes things. (*) I realize that I am extremely unlikely to convert anyone from writing const int ... to int const ..., but that said, there is one reason I prefer to do the latter.
(*) incuding a note that swapping the const with the type declaration at the very start is the one change that has no effect.
It makes for very easy readability, because for any instance of the word
const in a declaration, everything to the left of it is the type of what is const, and everything to the right is what actually is const.
Consider a declaration like:
int const * * const pointerToPointer;
The first const states that the integers at the end of the pointer chain are const, and they are to be found at * * const pointerToPointer. Meanwhile the second one states that an object of type pointer to pointer to const int is also const and that this object is pointerToPointer.
In the OP's case:
int const MyClass::showName(string id){
...
}
The type of what is const is int, and what is const is the return value from the function.
Meanwhile:
int MyClass::showName(string id) const {
...
}
Here the type of what is const is function(string) returning int, and what is const is the function itself, i.e. the function body.
what does "T const *[]" as parameter
type mean?
What's the difference
compared to "T *[]"?
And as last
question: why can't I pass a "T *[]"
to a function that requires a "T
const * []" as parameter?
Thank you for your help.
Tobias
As a type in general, it's an array of pointers to a constant T.
Try putting a name in it:
T const *x[];
and apply the usual rules: [] binds tighter than *, so it's an
array. Then the * means that its an array of pointers, and
finally, they all point to a constant T. (As usual, const
modifies whatever is to the left of it.)
As a parameter, of course, an array type is converted to
a pointer type, so we end up with a pointer to a pointer to
a constant T. This could also be written:
T const **
If you drop the const, you end up with:
T **
which is not the same thing as T const**.
And the reason you can't pass a T** or a T*[] to the first
form is to prevent things like:
void f(int const* p1[]; int const* p2)
{
p1[0] = *p2;
}
int const x = 10;
int* px[1];
f(px, &x);
*px[0] = 20; // Where does this write?
The fact that the declarations are written using [] is, in this
case, misleading, since the rules for pointers to pointers still
apply.
It's an array of pointers to constant objects of type T (i.e. the pointer can change, but you cannot call a non-const function, or modify a non-mutable data member on these objects). T *[] is an array of pointers to non-const ojects. You can't pass T *[] to a function requiring a T const *[] as it would invalidate the const correctness of the pointers.
See here for more information.
To start you probably know that const can be used to make either an object's data or a pointer not modifiable or both.
const Object* obj; // can't change data
Object* const obj; // can't change pointer
const Object* const obj; // can't change data or pointer
However you can also use the syntax:
Object const *obj; // same as const Object* obj;
The only thing that seems to matter is which side of the asterisk you put the const keyword. Personally I prefer to put const on the left of the type to specify it's data is not modifiable as I find it reads better in my left-to-right mindset but which syntax came first?
More importantly 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?
Edit:
So it sounds like this was an arbitrary decision when the standard for how compilers should interpret things was drafted long before I was born. Since const is applied to what is to the left of the keyword (by default?) I guess they figured there was no harm in adding "shortcuts" to apply keywords and type qualifiers in other ways at least until such a time as the declaration changes by parsing a * or & ...
This was the case in C as well then I'm assuming?
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.
The rule is:
const applies to the thing left of it. If there is nothing on the left then it applies to the thing right of it.
I prefer using const on the right of the thing to be const just because it is the "original" way const is defined.
But I think this is a very subjective point of view.
I prefer the second syntax. It helps me keep track of 'what' is constant by reading the type declaration from right to left:
Object * const obj; // read right-to-left: const pointer to Object
Object const * obj; // read right-to-left: pointer to const Object
Object const * const obj; // read right-to-left: const pointer to const Object
The order of the keywords in a declaration isn't all that fixed. There are many alternatives to "the one true order". Like this
int long const long unsigned volatile i = 0;
or should it be
volatile unsigned long long int const i = 0;
??
The first rule is to use whichever format your local coding standards
requires. After that: putting the const in front leads to no end of
confusion when typedefs are involved, e.g.:
typedef int* IntPtr;
const IntPtr p1; // same as int* const p1;
If your coding standard allows typedef's of pointers, then it really
should insist on putting the const after the type. In every case but
when applied to the type, const must follow what it applies to, so
coherence also argues in favor of the const after. But local coding
guidelines trump all of these; the difference isn't normally important
enough to go back and change all of the existing code.
There are historical reasons that either left or right is acceptable. Stroustrup had added const to C++ by 1983, but it didn't make it to C until C89/C90.
In C++ there's a good reason to always use const on the right. You'll be consistent everywhere because const member functions must be declared this way:
int getInt() const;
C uses a right-to-left syntax. Just read the declarations from right to left:
int var = 0;
// one is a pointer to a const int
int const * one = &var;
// two is a pointer to an int const (same as "const int")
const int * two = &var;
// three is a constant pointer to an int
int * const three = &var;
The first thing left to the "const" is affected by it.
For more fun read this guide:
http://cseweb.ucsd.edu/~ricko/rt_lt.rule.html
With
using P_Int = int *;
P_Int const a = nullptr;
int * const b = nullptr;
const P_Int c = nullptr;
const int * d = nullptr;
the variables a and b are the same type as each other but, somewhat confusingly, the variables c and d are not the same type as each other. My preference is for the first scenario, without the confusion: have const on the right of the type. N.B. it is the pointer that is const with a, b, and c; but the int is const with d.
When I work with the existing code, I follow the way already being used which is most of the time, const on left e.g const int a = 10; but if I got a chance to work from start I choose the "right way", means const on right e.g int const a = 10;, which is a more universal approach and straightforward to read.
As mentioned already, the rule is
const applies to the thing left of it. If there is nothing on the left then it applies to the thing right of it.
Here is the example code for basic use cases.
int main() {
int const a = 10; // Constant integer
const int b = 20; // Constant integer (same as above)
int c = 30; // Integer (changeable)
int * const d = &c; // Constant pointer to changeable integer
int const * e = &a; // Changeable pointer to constant integer
int const * const f = &a; // Constant pointer to constant integer
return 0;
}
At the end of the day, if there is no guideline to follow, this is subjective, and harmless to use either approach.