const int implicit conversion C++ - 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=ⅈ //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

Related

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++ pointer to constant error

In a book I'm reading about C++ (C++ for Dummies) there is a section that says the following:
int nVar = 10;
int* pVar = &nVar;
const int* pcVar = pVar; // this is legal
int* pVar2 = pcVar; // this is not
The book then goes on to explain:
The assignment pcVar = pVar; is okay -- this is adding the const
restriction. The final assignment in the snippet is not allowed since
it attempts to remove the const-ness of pcVar
My question is why is the last line not "legal". I don't understand how that impedes on the "const-ness" of pcVar. Thanks.
const int *pcVar = pVar;
int *pVar2 = pcVar;
If pcVar is const int *, that implies that the int it points to may be const. (It isn't in this case, but it may be.) So if you assign pVar2, which is a non-const int *, it still allows the int it points to to be modified.
So if pcVar actually pointed to a const int, and you assign an int * to its address, then that int * pointer (pVar2 in this case) will allow you, by dereferencing, to modify it, and that's illegal (it's a constraint violation, so it invokes undefined behavior).
All the compiler knows is that pcVar is a const int*. That is, it points to a const int. Just because you made it point at a non-const int doesn't matter. For all the compiler knows, the pointer value could have changed at some point to point at a truly const int. Therefore, the compiler won't let you convert from a const int* back to a int* because it would be lying about the constness of the object it was pointing at.
For a simpler example, consider:
const int x;
const int* pc = x;
int* p = pc; // Illegal
Here, x truly is a const int. If you could do that third line, you could then access the const int object through p (by doing *pc) and modify it. That would be bad - x is const for a reason.
However, in the example you gave, since you know that the original object was non-const, you could use const_cast to force the compiler into trusting you:
int* pVar2 = const_cast<int*>(pcVar);
Note that this is only valid if you know for certain that the object is non-const.
It's just saying you can't create a non-const pointer from one that was const (at least, not without a const_cast).
The idea behind const is to have objects that cannot be modified by accident. Getting rid of const through a simple assignment would be quite dangerous, and would allow things like this:
void function(int* m) {
*m = 20;
}
int main() {
const int x = 10;
//Oops! x isn't constant inside function any more, and is now 20!
function(&x);
}
Also, please check out The Definitive C++ Book and Guide List, it has lots of great references (C++ for dummies doesn't quite make the cut).
Mixing const and non-const is illegal. The reason being, if you tell the compiler that one location's value is const and then use another pointer to modify that value, you have violated the const contract you made with the first element.
pcVar stays the same but pVar2 points to a non-const, const can be added but not taken away. The compiler does not look at the original nVar being non-const, only the attempt to assign a const to a non const. Otherwise you could get around the const and change the value.
int * pVar = &nVar;
*pVar = 4 //is legal
const int* pcVar = pVar; // this is legal
*pcVar = 3 // this is not legal, we said the value was const thus it can not be changed
int* pVar2 = pcVar; // this is not legal because...
*pVar2 = 3 -> *pcVar = 3
The second line
int pVar = &nVar;
is error.
g++ compiler says.
error: invalid conversion from ‘int*’ to ‘int’

pointer and ampersand position with const in C++ [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Declaring pointers; asterisk on the left or right of the space between the type and name?
I've always been wondering what's the exact correct position to put * and &. it seems that C++ is pretty tolerant about where to put these marks.
For example I've seem pointer and ampersand been put on both left and right of a keyword or in the middle of two keywords, but confusingly sometimes they seems to mean the same thing, especially when used together with const
void f1(structure_type const& parameter)
void f2(structure_type const &parameter)
void f2(structure_type const *sptr);
void f2(structure_type const* sptr);
void f2(structure_type const * sptr);
The examples are not exhaustive. I see them everywhere while being declared or been passed to a function. Do they even mean the same thing? But I also see cases while putting * will affect which object being referred as a pointer (likely the case where * is in between two keywords).
EDITED:
int const *Constant
int const * Constant // this above two seem the same to me, both as pointer to a constant value
int const* Constant // EDIT: this one seems the same as above. instead of a constant pointer
const int * Constant // this is also a pointer to a constant value, but the word order changed while the pointer position stays the same, rather confusing.
int* const Constant
int * const Constant // instead, these two are constant pointers
So I concluded this:
T const* p; // pointer to const T
const T* p // seems same from above
T* const p; // const pointer to T
Still, this confused the hell out of me. Doesn't the compiler care about position and the spacing required for them?
Edit:
I want to know in general of the position matters. If yes in what cases.
White space matters only to the degree that it keeps tokens from running together and (for example) creating a single token, so (for example) int x is obviously different from intx.
When you're dealing with something like: int const*x;, whitespace on either size of the * makes absolutely no difference to the compiler at all.
The difference between a pointer to const int and const pointer to int depends on which side of the * the const is on.
int const *x; // pointer to const int
int *const x; // const pointer to int
The primary difference is readability when/if you define/declare multiple objects in the same declaration.
int* x, y;
int *x, y;
In the first, somebody might think that x and y are pointers to int -- but in fact, x is a pointer to an int, and y is an int. To some people's eyes, the second reflects that fact more accurately.
One way to prevent any misinterpretation is to only ever define one object at a time:
int *x;
int y;
For any of these, correct interpretation is fairly easy if you ignore whitespace entirely (except to tell you where one toke ends and another starts, so you know "const int" is two tokens) and read from right to left, reading * as "pointer to". For example: int volatile * const x; is read as "x is a const pointer to a volatile int".
int const *Constant
int const * Constant
int const* Constant
All of the above intend to declare a non constant pointer to a constant integer.
Simple rule:
If const follows after the * it applies to the pointer if not it applies to the pointed object. The spacing doesn't matter.
Both & and * placements in variable declaration are acceptable and only depends on your own flavour. They strictly mean the same thing, creating respectively a pointer and a reference.
However, the const keyword placement is primordial, as a int const* variable declares a constant pointer to a non-constant int, and const int* variable is a non-constant pointer to a constant int.

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

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.