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 *.
Related
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.
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=ⅈ //OK.
int *pi=ⅈ //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=ⅈ
Both cases are safe because you are only adding a constraint.
By doing:
int *pi=ⅈ
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
Today I noticed something strange about the type of 'this'. If you have something like this:
class C {
void funcA() {
funcB(this);
}
void funcB(C obj) {
//do something
}
};
You will of course get an error, because funcB() expects an object, while 'this' is a pointer. I accidentally did forget the asterisk, but was surprised by the error message, as it said:
no matching function for call to 'C::funcB(C* const)'
Where does the const come from, when funcA() is not constant?
That's saying that the this pointer itself as const -- i.e., you can't modify the pointer to point to different memory.
Back in the very early history of C++, before you could overload new and delete, or placement new was invented, this was a non-const pointer (at least inside the ctor). A class that wanted to handle its own memory management did so by allocating space for an instance in the constructor, and writing the address of that memory into this before exiting the constructor.
In a const member function the type you'd be dealing would be Class const *const this, meaning that what this points at is const (as well as the pointer itself being const).
C* const does not mean that the object of type C is constant. That would be C const* or const C*.
C* const means that the pointer itself is constant.
Which makes sense, since you cannot do
this = &something_else;
There is a difference between C const* and C * const. You need to understand the difference:
C const* means it is the object (pointed to by the pointer) which is constant.
C * const means it is the pointer itself which is constant.
So this by definition is a pointer of C * const type, so it cannot be modified, though the object pointed to by it can still be modified.
Note that it's not C const *, but C* const. I.e. (reading from right to left) constant pointer to C.
The pointer itself is constant, not the data pointed to.
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).
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.