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
Related
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.
I am working on an assignment in C++ and am having difficulties with a question.
We are given a function that can take anything in as an argument.We need to call this function, UberFunction, as an int, int*,int**, and char[].
My Code:
void CallUberFunctions() {
// There is a magic function, called "UberFunction" that is capable of taking
// anything for an argument. You need to call "UberFunction" with the
// following types: int, int* int** and char[]
// You also need to call "OtherUberFunction" in the namespace
// "uber_namespace" once, with no arguments.
UberFunction(42);
UberFunction((int*)42);
UberFunction((int**)42);
UberFunction((char[])'*');
}
Here is the error:
home/user/Desktop/cpp_refresher/cpp_refresher.cc:22:20: error: expected '(' for function-style
cast or type construction
I cannot get the char[] type to work properly, is my syntax above incorrect?
Try this fragment:
const int value = 42;
UberFunction(value); // int
UberFunction(&value); // int *
int * p_value = &value;
UberFunction(&p_value); // int * *
static const char text[] = "Hello World!\n";
UberFunction(text); // char []
Note that in the above example, the parameters are changing and not the return value.
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.
This question already has answers here:
how to avoid changing value of const in C
(4 answers)
Closed 8 years ago.
In an interview, I was asked to change constant value in CPP, but I said in CPP it is not possible but in c it is possible using pointer.
Interviewer said that using CPP it is possible and asked me to try but I couldn't and I came back to my room and tried again but what I figured out that I was able to change in C but same code was getting error when compiled as C++.
#include<stdio.h>
main()
{
const int i=5;
int *p;
p=&i;
*p=8;
printf("%d",i);
}
This code is changing the constant value of i in c but when I compile in CPP then
I get an error:
invalid conversion from 'const int*' to 'int*'
Given your error, the actual program must have been the following:
#include<stdio.h>
main()
{
const int i=5;
int *p;
p=&i;
*p=8;
printf("%d",i);
}
This produces a warning with gcc:
warning: assignment discards 'const' qualifier from pointer target type
and an error with g++:
error: invalid conversion from 'const int*' to 'int*'
So, let's change the title of your question to a better one:
Why does C allow conversion from const int * to int *, but C++ doesn't?
The reason why one gives a warning and another gives an error is not because one allows you to discard const qualifier and the other doesn't. It's merely because the C standard leaves such incorrect actions as undefined behavior, while the C++ standard specifically marks it as an error. Either way, doing this is wrong.
You can read this similar question asking why this is possible in C.
What I think interviewer wanted this:
int n = 0;
int const *p = &n;
The expression &n has type “pointer to int.” The declaration for p converts &n to type “pointer to const int,” adding a const qualifier in the process. This is a valid qualification conversion. This conversion in no way invalidates n’s declaration. The program can still use n to alter the int object, even if it can’t use *p for the
same purpose.
*p = 5; // wrong
But
n = 5; // OK
now *p is 5 although it is const type!
Now try to run this code in GCC or g++, it will work:
#include<stdio.h>
int main()
{
int n = 0;
const int *p;
p=&n;
printf("%d\n",*p);
n = 5;
printf("%d\n",*p);
return 0;
}
EDIT: The only way to change the value of const qualified object in C and C++ both is, change the value in the initialization statement:
const int i = 5 ---> const int i = 8
This is why const_cast exists, I believe the interviewer asked this because they have to deal with poorly designed library code they have no control over, however normally you shouldn't have to resort to using it in production.
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**...).