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

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.

Related

Can I have a pointer on pointer on const in C++?

Basically I am wondering whether something like
f(const void* a){
// This is also what `(char**) a` would do behind the scenes
char** string_a_ptr {reinterpret_cast<char**>(const_cast<void*>(a))};
// ...
is possible while preserving the const qualifier.
My question came up during an exercise about C-Arrays in C++. Because of C, I had to pass a function pointer with const void* arguments. In this case it was pointing on an array of C-strings. To cast it to the correct type I had to cast the const away. Is there a way in C++ to get something like a "(const char*)*"` pointer?
I have tried out const char** (without the const_cast) which yields
reinterpret_cast from type ‘const void*’ to type ‘const char**’ casts away qualifiers
and (const*)*, which gives a syntax error
expected type-specifier before ‘(’ token
This is a purely academic question. I am aware, that the problem can be solved easier and saver using std::string and #include <algorithm>.
While I am at it, are there advantages of sometimes using C-constructions in C++ or should they always be avoided if possible? I only did some small scale exercise problems with C code in C++, but it already causes quite a few headaches and forces me to look really closely under the hood, even though I have written a fair amount of C code in my life.
Or is it would you rather recommend using the extern C qualifier and writing C code in pure C?
That would be a char* const *.
There are three places in a double pointer to put const:
const char**
Pointer, to a pointer, to a character you cannot change.
char *const *
pointer, to a pointer you cannot change, to a character.
char ** const
pointer you cannot change, to a pointer, to a character.
You can mix these to make different parts const.
I believe this is what you're looking for:
const char * const * string_a_ptr = static_cast<const char * const *>(a);
[Live example]
You could even drop the first const if you want (and it makes sense).
Explanation:
const void * a means that a points to something (void) which is const. Therefore, if you cast a to another pointer, it must also point to something that is const. In your case, you're casting it to a pointer to char*. That char* must therefore be const. The syntax for creating a constant pointer (not a pointer to a constant) is to put the const to the right of the *. Hence, char* const *.

const int implicit conversion C++

i'd like to know if there is a sort of implicit conversion between variables when using a pointer to constant integer ,
for example , if i use an address of a variable type int or const int it accepts to store it ,
however if i use a normal pointer to int it doesn't allow storing the address of the const int type,why is this?, thanks in advance
int i=4;
const int ii=4;
//pointer to constant int
const int *pci=&i; //OK.
pci=&ii; //OK.
int *pi=&ii; //ERROR invalid conversion.
The first and second assignments initialize pci to constly point to an int or a const int.
So you might have one of two situations:
const int* which points to an int.
pci=&i;
const int* which points to a const int.
pci=&ii;
Both cases are safe because you are only adding a constraint.
By doing:
int *pi=&ii;
You make an int* point to a const int which means you remove a constraint.
Since removing a constraint might be risky, this requires you to use a const_cast.
int* pi = const_cast<int*>(&ii);
Note that forcibly removing the const modifier is something you should ask yourself twice if you really wanna do, since it also make the const modifier somewhat meaningless because you will be able to modify that "constant" address through the converted variable.
Simply assigning a pointer to a const element to a pointer to a non-const element is not allowed, since that would silently dismiss the const-ness of the original, which is something that you don't want, and can also be a source of silent bugs, which is one of the reasons it's not allowed.
However, if this is really what you want, you can explicitly request to remove the const qualifier by using const_cast

Why cant I pass a non const pointer to a function taking a reference to a pointer to a const as its argument

Here's a code snippet that hopefully conveys what I'm trying to do:
void updatePointer(const int*& i)
{
i++;
}
int main() {
int array[5];
int* arrayPtr = array;
updatePointer(arrayPtr );
return 0;
}
This gives compiler error:
prog.cpp: In function ‘int main()’:
prog.cpp:16: error: invalid initialization of reference of type ‘const int*&’ from
expression of type ‘int*’
prog.cpp:5: error: in passing argument 1 of ‘void updatePointer(const int*&)’
Supposing that you could do it, you could write the following:
const int c = 0;
void updatePointer(const int* &i) {
i = &c;
}
int main() {
int *ptr;
updatePointer(ptr);
*ptr = 1; // attempt to modify the const object c, undefined behavior
}
The purpose of const is to ensure that user code cannot attempt to modify a const object unless it contains a const-cast (or equivalent). So the compiler has to refuse this code. Forbidding a const int*& from binding to an int* is the only place in the code above that's reasonable for the compiler to refuse: every other line is fine.
It's the same reason you can't implicitly convert int** to const int **.
Aside from the motivation in terms of const-safety, you can think if it in terms of int* being a different type from const int*, that just so happens to be convertible to it. Likewise, you can convert int to double, but a double& can't bind to an int lvalue. That's not the full reason, because actually int* and const int* have the same size and representation, whereas int and double don't. So there could be a special-case to allow it if not for the fact that it would break the const system.
The reason that C++ has both const and non-const overloads for strchr is related to this issue: your function updatePointer modifies its input rather than returning the updated value, but the principle is similar. The C-style single strchr allows you to "launder" a pointer-to-const into a pointer-to-non-const without a cast, and it's a hole in the const system. C++ (a) has overloading and (b) has a stricter type system than C, so it closes that hole.
If you want your real function updatePointer to work like strchr -- examine the data pointed to and compute a new value for the pointer, then you're in the same situation that strchr is. That's regardless of what it does with the new value (return it in the case of strchr, write it back in the case of updatePointer), because the issue is that you want the new pointer to have the same const-qualification as the input. You need to provide either const- and non-const overloads or a function template.
If you only need your real function updatePointer to move a pointer by a certain distance, regardless of the data pointed to, you could use std::advance instead.
What you wrote is a function taking a reference to a pointer to a const int. What you're asking for would be
updatePointer(int* const & i);
However this doesn't make much sense. Passing a reference to a pointer seems to imply that you intend to modify the pointer, but you cannot do it because it is declared const. As it is you'd obtain the same effect by just passing your pointer as in
updatePointer(int* i);
Found this
Copied here in case the link breaks in future:
The reasoning is a little awkward to comes to grips with. The main question is:
Since a "const int&" can be bound to an "int", why can't a "const int*&" be bound to a "int*"?
Basically, once you add a level of indirection (a pointer) then the rules change. With just a single level of indirection (as in a single *), the rule can be stated as:
A reference to a pointer to a cv-qualified type can be bound to anything of that same type whose cv-qualifications are less than or equal to that of the pointer (which is a reference).
(Read that a few times.)
So the reason a "const int*&" can't be bound to a "int*" is because "const int*" and "int*" are two different types (underlined part of the rule is broken).

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

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.

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.