C++: what does "T const *[]" mean? - c++

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.

Related

How can const be applied to template argument types outside of the parameter list in C++?

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

Why do I get invalid conversion from int** to const int**? [duplicate]

I have a function that receives float** as an argument, and I tried to change it to take const float**.
The compiler (g++) didn't like it and issued :
invalid conversion from ‘float**’ to ‘const float**’
this makes no sense to me, I know (and verified) that I can pass char* to a function that takes const char*, so why not with const float**?
See Why am I getting an error converting a Foo** → const Foo**?
Because converting Foo** → const Foo** would be invalid and dangerous ... The reason the conversion from Foo** → const Foo** is dangerous is that it would let you silently and accidentally modify a const Foo object without a cast
The reference goes on to give an example of how such an implicit conversion could allow me one to modify a const object without a cast.
This is a very tricky restriction. It is related to the aliasing rules of the language. Take a look at what the standards say, because I have faced this once before:
(Page 61)
[Note: if a program could assign a
pointer of type T** to a pointer of
type const T** (that is, if line //1
below was allowed), a program could
inadvertently modify a const object
(as it is done on line //2). For
example,
int main() {
const char c = 'c';
char* pc;
const char** pcc = &pc; //1: not allowed
*pcc = &c;
*pc = 'C'; //2: modifies a const object
}
—end note]
Other anwers have detailled why this is an error in C++.
Let me address the question behind your question. You wanted to state, in the interface of your function, that your function will not modify float values contained in the array. Nice intention, and enables that your function is called with const float ** arrays. The question behind your question would be, how to achieve this without resolving to ugly casts.
The correct way to achieve what you wanted is to change the type of your function parameter to const float * const *.
The additional const between the stars assures the compiler that your method will not try to store pointers to const float in the array, since this type declares that the pointer values are also const.
You can now call this function with float ** (which was the example in your question), const float **, and const float * const * arguments.
If you converted the parameter to const float** you could then store a const float* at the memory location where the parameter points to. But the calling function thinks that this memory location is supposed to contain a non-const float* and might later try to change this pointed-to float.
Therefore you cannot cast a float** to a const float**, it would allow you to store pointers to constants in locations where pointers to mutable values are expected.
For more details see the C++ FAQ Lite.

C++ const used twice in static array declaration

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.

What does `const T* const` mean?

I was reading a C++ template example, and part of the template signature confused me.
Am I reading this correctly:
const T* const foo;
Is foo a const* to a const T?
Yes, it's a constant pointer to a constant T. I.e., you can neither modify the pointer, nor the thing it points to.
const T* would only forbid you to modify anything the pointer points to, but it allows you (within the bounds of the language) to inspect the value at *(foo+1) and *(foo-1). Use this form when you're passing pointers to immutable arrays (such as a C string you're only supposed to read).
T * const would mean you can modify the T value pointed to by foo, but you cannot modify the pointer itself; so you can't say foo++; (*foo)++ because the first statement would increment (modify) the pointer.
T * would give you full freedom: you get a pointer into an array, and you can inspect and modify any member of that array.
Yes; that is exactly what it means.
Since there is always a little confusion about const when using pointers, there are the following possibilities:
const T * aConstant
means aConstant is a variable pointer to a constant T.
T const * aConstant
does exactly the same.
T * const aConstant
declares that aConstant is a constant pointer to a variable T and.
T const * const aConstant (or const T * const aConstant)
declares a constant pointer to a constant T.
This is a const pointer-to-const T. So if T was an int, then array is a pointer to an int that is const in two ways:
pointer-to-const: the value that the pointer is pointing to cannot be changed (or pointing to const int)
const pointer: the memory address stored in the pointer cannot change
This is also the same as T const * const array
See wiki on const correctness.
Yes, foo is a constant pointer to constant T.
Yes.
const T*
makes the elements of the array const... at least, as far as foo is concerned.
foo[0] = T(); // Illegal!
foo[1] = T(); // Illegal!
foo[2] = whatever; // Illegal!
const
makes foo a constant pointer. Therefore, this is illegal:
foo = &some_array;
The variable
foo
...if you don't know what this is, you should seriously consider going to preschool.
Yes it is, i think name of var(const) is what stumbles you.
Yes, it just simply means that not only can't you change what foo points to, but you also can't change the value of foo itself so that it points to some other T instance.
simply parse it like this
const<ptr<const<T>>> foo
although it is illegal, but I think everyone can grasp its essence.

Why am I getting an error converting a ‘float**’ to ‘const float**’?

I have a function that receives float** as an argument, and I tried to change it to take const float**.
The compiler (g++) didn't like it and issued :
invalid conversion from ‘float**’ to ‘const float**’
this makes no sense to me, I know (and verified) that I can pass char* to a function that takes const char*, so why not with const float**?
See Why am I getting an error converting a Foo** → const Foo**?
Because converting Foo** → const Foo** would be invalid and dangerous ... The reason the conversion from Foo** → const Foo** is dangerous is that it would let you silently and accidentally modify a const Foo object without a cast
The reference goes on to give an example of how such an implicit conversion could allow me one to modify a const object without a cast.
This is a very tricky restriction. It is related to the aliasing rules of the language. Take a look at what the standards say, because I have faced this once before:
(Page 61)
[Note: if a program could assign a
pointer of type T** to a pointer of
type const T** (that is, if line //1
below was allowed), a program could
inadvertently modify a const object
(as it is done on line //2). For
example,
int main() {
const char c = 'c';
char* pc;
const char** pcc = &pc; //1: not allowed
*pcc = &c;
*pc = 'C'; //2: modifies a const object
}
—end note]
Other anwers have detailled why this is an error in C++.
Let me address the question behind your question. You wanted to state, in the interface of your function, that your function will not modify float values contained in the array. Nice intention, and enables that your function is called with const float ** arrays. The question behind your question would be, how to achieve this without resolving to ugly casts.
The correct way to achieve what you wanted is to change the type of your function parameter to const float * const *.
The additional const between the stars assures the compiler that your method will not try to store pointers to const float in the array, since this type declares that the pointer values are also const.
You can now call this function with float ** (which was the example in your question), const float **, and const float * const * arguments.
If you converted the parameter to const float** you could then store a const float* at the memory location where the parameter points to. But the calling function thinks that this memory location is supposed to contain a non-const float* and might later try to change this pointed-to float.
Therefore you cannot cast a float** to a const float**, it would allow you to store pointers to constants in locations where pointers to mutable values are expected.
For more details see the C++ FAQ Lite.