static_cast void* char* vs static_cast void** char** - c++

If I do the following all is ok:
char* cp = "abc";
void* vp = NULL;
vp = static_cast<void*>(cp);//ok
cp = static_cast<char*>(vp);//ok
But the following is not:
char** cpp = &cp;
void** vpp = NULL;
vpp = static_cast<void**>(cpp);//error C2440: 'static_cast':
//cannot convert from 'char **' to 'void **'
cpp = static_cast<char**>(vpp);//error C2440: 'static_cast':
//cannot convert from 'void **' to 'char **'
Please can someone explain to me why the second examples are not allowed. Please don't quote the C++ standard as your whole answer, because I've already seen answers that quote it, and I don't understand what they meant. I want to understand why the second examples don't work (ie. if you could give an example where it would be dangerous that would be a great help). Because I don't get it. To me, both examples are casting pointers. Why does an additional level of indirection make any difference?

A void * pointer can point at "anything", and it is valid to convert all pointers to a void *, and it is valid to convert all pointers from void * to some other type.
However, a void ** is a pointer that points to a void * value. And a char ** is a pointer that points to char * value. These types don't point to the types that are convertible from one another. You can, if you NEED to do this, use void **vpp = reinterpret_cast<void **>(cpp);, but it's "not safe" (you are basically telling the compiler "Look, I know what I'm doing here, so just do it", which may not do what you actually expected...)

The restriction is to avoid breaking the type system. The first conversion is fine:
type *p = ...;
void *vp = p;
While you are giving away the type, you cannot inflict too much damage to the original value without since there is little to be done with a void object and all changes to vp are local to the pointer and cannot affect p.
If the second case was allowed:
type **p = ...;
void **vp = p;
Then perfectly looking and correct code could break your application. For example:
int *parray[10];
int **p = parray;
void **vp = p;
*vp = new double(); // now parray[0] is a pointer to a double object,
// not a pointer to an int!!!
The type system has been subverted.
That is, the problem is that in the second case there are operations that can be applied to the destination pointer that can modify the original object and cause bugs. Similar examples can be found with const other cases (you can convert int* to const int*, but you cannot convert int** to const int**...).

Related

C vs. C++, handling of void** pointers

I found out that using a C compiler the code below works but not with a C++ compiler. I understand that casting to void** is the correct usage but I can't understand why it compiles with the C compiler even if I use the void* (commented out).
#include <stdio.h>
int fn(void **arg)
{
int *pvalue = *(int**)arg;
*pvalue = 200;
return 0;
}
int main()
{
int value = 99;
int *pvalue = &value;
// fn((void *)&pvalue); // works only in C
// error C2664: 'int fn(void **)': cannot convert argument 1 from 'void *' to 'void **'
fn((void **)&pvalue); // correct, works for both C/C++
printf("%d", value);
return 0;
}
Can someone explain why this is the case?
In C there is allowed to assign a pointer of the type void * to a pointer of other type. This takes place in this call
fn((void *)&pvalue)
where the argument has the type void * that is assigned to the function parameter that has the type void **.
int fn(void **arg)
{
int *pvalue = *(int**)arg;
*pvalue = 200;
return 0;
}
However such an assignment in general is unsafe. For example the value of a pointer of the type void * can not be properly aligned to be assigned to a pointer of other type.
So it was decided to not allow such an assignment in C++ to make programs more safer.
I can't understand why it compiles with the C compiler even if I use the void* (commented out).
It compiles because void* is implicitly convertible to other pointers in C.
fn((void **)&pvalue); // correct, works for both C/C++
This may be well-formed because of the cast, the standard doesn't technically give explicit guarantee that conversion to void** and back yields the same address.
While this may be likely to work in practice, there is no reason to not use void* as the function argument instead, which does have the guarantee. As a bonus, you won't need the cast in the call. Like this:
int fn(void *arg);
fn(&pvalue); // correct, works for both C/C++
Of course, this is assuming type erasure is needed in the first place. Avoid void* when it is not needed.
For avoidance of doubt, there is nothing correct in
fn((void **)&pvalue);
It is just as incorrect as
fn((void *)&pvalue);
The correct way to use the API is to do
int fn(void **arg)
{
int *pvalue = (int *)*arg;
*(int *)pvalue = 200;
return 0;
}
or
int fn(void **arg)
{
*(int *)*arg = 200;
return 0;
}
with
int main()
{
int value = 99;
void *pvalue = (void*)&value;
fn(&pvalue);
printf("%d", value);
return 0;
}
You're not allowed to access an object using any other pointer type, other than the declared type, compatible type, or a character type. Furthermore, while void * is used as a generic pointer type to all sorts of objects in C, there is no generic pointer to a pointer type in C - other than void *!
And this is the reason why the void ** is almost always a sign of a design error in APIs - most usages are just wrong.

Passing 'const' pointer which points to another pointer in c++

The following code fails to compile with two errors on the line 'func(&pobj);' stating "Cannot convert 'X * *' to 'const X * *' in function main()" and "Type mismatch in parameter 1 (wanted 'const X * *', got 'X * *') in function main()" even though its the correct way to pass pointer parameters. And also on commenting this particular line i.e 'func(&pobj);' and uncommenting the two lines above it which declares a new 'const' pointer 'pp' of required type (in parameter of func) but still throws an error on the line which declares and assigns 'pp' saying "Cannot convert 'X * *' to 'const X * *' in function main()".
using X = int;
void func(const X **);
int main() {
X *pobj = new X(58);
// const X **pp = &pobj; // ERROR
// func(pp);
func(&pobj); // ERROR
}
I believe that this is the correct way to pass constant pointers as parameters and I just don't understand why the program fails to compile. Can anyone point out the fault in the code above and suggest me the correct logic/syntax if I am wrong? Thanks in advance.
UPDATE:
This question was marked as duplicate but it doesn't have the answer that solves the problem at hand. Thus I would love it if the Stack Overflow community would help me to solve my problem here. Thanks.
Do this:
const X * pobj = new X(58);
// ^^^^^^
func(&pobj);
Now pobj is a pointer-to-const-X, and its address is of type const X ** as required.
If you want to retain the original (mutable) pointer, you need to make a new const pointer first:
X * p = new X(58);
const X * q = p;
func(&q);
You will need to apply const to pointer-to-pointer:
void func(X *const *);
...
X * const *pp=&pobj; // ERROR
func(&pobj); // ERROR
...
void func(X * const * obj) { // module code goes here
}
If the answer of Ajay is not appropriate, because You cannot change the interface of func(),
and if the answer of Kerrek does not work, because func() changes the pointer, which must be assigned back, that does not happen:
X * p = new X(58);
const X * q = p;
func(&q);
p = q; // errror
then simply use a cast:
func(const_cast<const X**>(&p))

Cannot seem to cast void* to struct in c++

I have a very simple method with the following prototype:
void *station_0(void* p1);
I am calling it like this:
product_record r;
pthread_create(thread, NULL, station_0, (void *)&r);
Inside this method all I need to do is cast p1 to an already defined struct product_record, I am currently trying this inside of my method:
product_record p = (product_record)p1
but the compiler complains on that line(above) saying error: invalid conversion from 'void*' to 'int' [-fpermissive]
I don't think I understand this warning at all. Why cannot I simply cast a void* to my struct?
You need two steps - convert the void pointer to a product_record pointer and then de-reference that. This can be done in the line
product_record p = *(static_cast<product_record *>(p1));

get the memory address of constant variable in c++

How can I get the memory address of a constant variable in c++. When I try to get this I get an error.
int const nValue = 5;
int * pnPtr = &nValue;
The error message is given below. I'm using visual studio 2010.
Error 1 error C2440: 'initializing' : cannot convert from 'const int *' to 'int *'
Is there any method to do this?
"Is there any method to do this?"
Sure. You need a const int* pointer to get this address, as the error message says:
int const nValue = 5;
const int * pnPtr = &nValue;
// ^^^^^
An int* pointer would allow to modify the nValue, which is not legal, and that's why the compiler complains.
As for your comment. A const int* can be used to point to a regular int and a const int. The point is just you can't use it to modify the underlying memory at the address it holds.
The pointer variable itself isn't const and can be changed to a different address.
If you want both attributes you'll need to write:
const int const * pnPtr = &nValue;
// ^ ^
// | + prevents changing the pointer after initialization
// +- prevents changing the underlying memory
You need to use a pointer to a const int value like this:
int const *ptr = &nValue;
C++ is strict regarding const-correctness, and this is a good thing.

non-const pointer argument to a const double pointer parameter

The const modifier in C++ before star means that using this pointer the value pointed at cannot be changed, while the pointer itself can be made to point something else. In the below
void justloadme(const int **ptr)
{
*ptr = new int[5];
}
int main()
{
int *ptr = NULL;
justloadme(&ptr);
}
justloadme function should not be allowed to edit the integer values (if any) pointed by the passed param, while it can edit the int* value (since the const is not after the first star), but still why do I get a compiler error in both GCC and VC++?
GCC: error: invalid conversion from int** to const int**
VC++: error C2664: 'justloadme' : cannot convert parameter 1 from 'int **' to 'const int **'. Conversion loses qualifiers
Why does it say that the conversion loses qualifiers? Isn't it gaining the const qualifier? Moreover, isn't it similar to strlen(const char*) where we pass a non-const char*
As most times, the compiler is right and intuition wrong. The problem is that if that particular assignment was allowed you could break const-correctness in your program:
const int constant = 10;
int *modifier = 0;
const int ** const_breaker = &modifier; // [*] this is equivalent to your code
*const_breaker = & constant; // no problem, const_breaker points to
// pointer to a constant integer, but...
// we are actually doing: modifer = &constant!!!
*modifier = 5; // ouch!! we are modifying a constant!!!
The line marked with [*] is the culprit for that violation, and is disallowed for that particular reason. The language allows adding const to the last level but not the first:
int * const * correct = &modifier; // ok, this does not break correctness of the code