Related
I know from this answer that a pointer const int** z is supposed to be read as
Variable z is [a pointer to [a pointer to a const int object]].
In my humble opinion, this would mean if z=&y then y should be a pointer to a const int object. However, the following code also compiles:
int x=0;
int const* y=&x;
const int** z=&y;
Why is an int const* object i.e. a const pointer to an int instead of a pointer to a const int acceptable to be the pointed object of z?
You are misunderstanding what the const refers to. A const always refers to the element to the left of it - unless it is the leftmost element itself, in which it refers to the element to the right.
This means that
int const * is a pointer to a const int, not a const pointer to int as you think. To get that, you would have to write int * const
int const * and const int * are two ways of writing exactly the same: a pointer to a const int.
You get it right if you read declarations from right to left. If const is the leftmost element, add a "that is" before it when reading. Ex:
const int *: pointer to int that is const.
int const *: pointer to const int.
int * const: const pointer to int.
const int * const: const pointer to int that is const.
int const * const: const pointer to const int.
Note that 1/2 are the same, and 4/5 are the same. 1 and 4 are called "west const" since const is on the west/left side, while 2 and 5 are called "east const".
Why is an int const* object i.e. a const pointer to an int
No.
int const * and const int * are the same type.
People sometimes prefer writing int const * because it reads right-to-left as "pointer to a const int", whereas const int * really reads as "pointer to an int (which is const)".
A const pointer to an int is int * const.
Try it:
int a = 42;
const int * y = &a;
int const * z = &a;
*y = 24; // compile error assigning to const
*z = 24; // compile error assigning to const
int b = 0;
y = &b;
z = &b; // re-pointing non-const pointers is fine
*z = 1; // still a compile error
int * const x = &a;
*x = 24; // fine, assigning via pointer to non-const
x = &b; // error reassigning a const pointer
Why the following code is giving me an error
Test.cpp:23:10: error: invalid conversion from ‘const int*’ to ‘int*’ [-fpermissive] return array;
#include <iostream>
#include <stdio.h>
#define MAX_ELEMENTS 5
class CBase
{
public:
CBase()
{
for(int i = 0; i < MAX_ELEMENTS; i++)
{
array[i] = 0;
}
}
~CBase()
{
// Nothing
}
int * GetArray() const
{
return array;
}
private:
int array[MAX_ELEMENTS];
};
int main ()
{
CBase b;
return 1;
}
EDIT: I understand that I should return a const int * but then I tried something below which works fine, request to explain the reason for allowing this and not allowing the above.
#include <iostream>
#include <stdio.h>
class CBase
{
public:
CBase():ptr(NULL)
{
}
~CBase()
{
delete ptr;
}
int * ptr;
public:
int * GetPtr() const
{
return ptr;
}
};
int main ()
{
CBase b;
return 1;
}
Imagine code like this:
const CBase b;
int *array = b.GetArray();
array[0] = 5; // ooops! b changed but we declared it const!?
So as already mentioned in the comments, it does break const-correctness of your code. What you need to do is either declare GetArray() non-const, or make it return a pointer to a const int.
const int * GetArray() const
{
return array;
}
Now, code like this would not compile:
const CBase b;
const int *array = b.GetArray();
array[0] = 5;
EDIT
To answer your other question from the comments above: When you call a method that returns a value and you assign this return value to some variable, than the return value is copied to your variable and afterwards discarded. So when your calling code changes the value of this variable this has no effect on the value or variable that was initially returned. That is why a const member function can return some of the class' data members. However, when you return a pointer to a data member, than the calling code can manipulate the value of this member. Still, the pointer is copied, but even the copy points to the memory location where the class member is stored and thus you could manipulate its value.
Your method should return a const int* instead.
const int * GetArray() const
{
return array;
}
Its simple you need to either declare GetArray() non-const, or make it return a pointer to a const int.
const int * GetArray() const
{
return array;
}
The reason is that if you return non constant array then as array is returned as pointer so its value can be changed by function which gets its value so constant function indirectly results in changing the value so you need to return constant array.
I want to have a pointer to a constant, and pass its address to a function that will increment it.
int f1(const int **ptr) {
int n = **ptr; //use pointer
(*ptr)++; //increment pointer
return n;
}
void foo(const int *data) {
const int *p = data;
const int n = f1(&p); //error: invalid conversion from ‘const int**’ to ‘int**’
//error: initializing argument 1 of ‘int LevelLoader::readWord(byte**)’
}
How do I declare the pointers?
Try
int f1(const int *& ptr) {
int n = *ptr;
++ptr;
return n;
}
void foo(const int *data) {
const int *p = data;
const int n = f1(p);
}
instead.
The error message indicates that LevelLoader::readWord doesn't take a const byte**.
This:
const int *data;
is a pointer to a constant integer. That means that you are not allowed to change the data pointed to by data. You can read and copy the data, but you can't do:
(*data) = 5;
That's illegal in C++ because it was declared const int *.
If you take the address of a const int *, you get a const int **, which is a pointer to a pointer to a constant integer. So you still cannot change the integer. Any attempt to do so will cause the compiler to complain.
If you want to be able to change the integer, then foo and f1 should not take const int * values. They should take int * values.
I don't want to modify the constant. I want to modify the pointer to it (p in foo())
So, you're given a pointer. And you want to increment the pointer. So just do so:
void foo(const int *data) {
const int *p = data;
data++;
}
You have incremented the pointer. This will not affect the caller to foo, as the pointer itself is copied by value.
Check again, this code is correct. It shouldn't generate the errors you claim.
EDIT: You fixed the void problem so answer amended accordingly.
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
int i1 = 0;
int i2 = 10;
const int *p = &i1;
int const *p2 = &i1;
const int const *p3 = &i1;
p = &i2;
p2 = &i2;
p3 = &i2;
cout << *p << endl
<< *p2 <<endl
<< *p3 <<endl;
return 0;
}
The code can be compiled with both VC6.0 and VC2010.
But I have questions as blow:
const int *p = &i1;
It means what the "p" points can not be modified,but p can not be modified,am I right?
so
p = &i2;
this line can be complied,yes?
This line:
int const *p2 = &i1;
In my mind,this means p2 can not be modified while what p2 points can be changed, am i right?
Why the
p2 = &i2;
can be compiled?
About this line:
const int const *p3 = &i1;
p3 = &i2;
Oh,god... I am crazy. I have no idea why this line can be compiled with no error...
Can any body help me?
Another code which confused me is here:
class Coo2
{
public:
Coo2() : p(new int(0)) {}
~Coo2() {delete p;}
int const * getP() const
{
*p = 1;
return this->p;
}
private:
int* p;
};
why this code can be compiled?
In
int const * getP() const
I have change the value or *p !
Here we consider 4 types of pointers declarations:
int * w;
It means that w is a pointer to an integer type value. We can modify both the pointer and its content. If we initialize w while declaration as below:
int * w = &a;
Then, both of below operations are viable:
w = &b;(true)
*w = 1;(true)
int * const x;
It means x is a constant pointer that points to an integer type value. If we initialize x while declaration as below:
int * const x = &a;
Then, we cannot do: x = &b;(wrong) because x is a constant pointer and cannot be modified.
However, it is possible to do: *x = 1;(true), because the content of x is not constant.
int const * y; //both mean the same
const int * y;
It means that y is a pointer that points to a constant integer value. If we initialize y while declaration as below:
int const * y = &a;
Then, it is possible to do: y=&b;(true) because y is a non-constant pointer that can point to anywhere.
However, we cannot do: *y=1;(wrong) because the variable that y points to is a constant variable and cannot be modified.
int const * const z; //both mean the same
const int * const z;
It means that z is a constant pointer that points to a constant integer value. If we initialize z while declaration as below:
int const * const z = &a;
Therefore, non of below operations are viable:
z = &b;(wrong)
*z = 1;(wrong)
With the help of pointer, you can actually do two things.
You can change the data it is pointing to but cannot point to a different memory location.
You can point it to a different memory location but cannot change the data it is pointing to.
Now, when you say, int const* ptr or int const* ptr, it falls under first category. It's same as -
const int num = 5; // Both mean the same.
int const num = 5;
To, actually not able to change to a different location, i.e., pointer to a constant location but be able to modify the data, the semantics should be int* const. Since the content of the pointer is a constant, it should be initialized while declaration.
int num = 5;
int* const ptr; // Wrong
ptr = # // Wrong
int* const ptr = #
*ptr = 100;
However, there is a third kind. Constant pointer to a constant location, which can neither point to a different memory location nor change the data it is pointing to. ( i.e., const int* const )
And now answering the questions, the first two can be compiled because they are not pointing to constant locations. So, they can be modified at later stages too.
const int const *p3 = &i1;
p3 = &i2; // Wrong
In the above snippet, p3 is a constant pointer to a constant location. So, it cannot be modified.
const at the end of a member function says it is not going to change the state of the object. When you say *p = 1;, you are not changing the state of the object. p still points to the same memory location. This is not allowed to do -
int const * Coo2::getP() const
{
*p = 1; // State of `p` is still not modified.
p = new int ; // Error: Changing the memory location to which p points.
// This is what changing the state of object mean and
// is not allowed because of `const` keyword at the end of function
return this->p;
}
Hope, now you understand why the program compiles :)
int const * p; and const int * p are the same. It is when the const comes after the * that
the semantics of the expression change.
I know, it's crazy.
const int *p = &i1;
int const *p2 = &i1;
These both declare non-const pointers to const data.
That is, using p, you cannot change the data it points to. However, you can change the pointer itself, for example, by assigning as p = &i2 which is legal. But *p = 87987 is illegal, as the data p points to is const!
--
int * const p = &i1;
This declares const pointer to non-const data. That is, p=&i2 is illegal, but *p = 98789 is legal.
--
const int * const p = &i1;
This declares const pointer to const data. That is, now both p=&i2 and *p=87897 are illegal.
The two are exactly the same. What matters is the position of the qualifier relative to the asterisk (*):
int const *p; // normal pointer to const int
const int *p; // ditto
int *const p; // const pointer to normal int (rarely useful)
int const * const p; // const pointer to const int
Here is a pointer to a constant:
const int* p;
The following statement is illegal, because it attempts to change the
value of a constant:
*p = 3;
But this one is legal, because the pointer itself is not a constant:
p = &x;
On the other hand, this declaration shows a constant pointer to a variable.
int* const p;
In that case, the following statement is legal, as the variable can be changed:
*p = 3;
but this one is not, because it attempts to change the value of a constant.
p = &x;
Reference link:http://faculty.cs.niu.edu/~freedman/241/const-ptrs.txt
No, the const keyword before the * means that the variable you are pointing to is a "const" variable and only it can not be modified.
If you want a pointer that can't be reassigned then you need to declare it as Foo* const p = &bar;
If you want a pointer that points to a "const" object that can't be reassigned declare it as const Foo* const p = &bar
It is perfectly fine to have a pointer of const int* foo be assigned to a pointer of const int* const bar just like it is fine to have an int's value assigned to a const int. Think of it in the same manner.
int const * is the same as const int *
Succinctly; each combination of read/write int & pointer;
int main() {
int a,b;
int* w; // read/write int, read/write pointer
w= &b; // good
*w= 1; // good
int* const x = &a; // read only pointer, read/write int
// x = &b; // compilation error
*x = 0; // good
int const * y; // read/write ptr, read only int
const int * y2; // " " "
y = &a; // good
// *y = 0; // compilation error
y2 = &a; // good
// *y2 = 0; // compilation error
int const * const z = &a; // read only ptr and read only int
const int * const z2 = &b; // " " " "
// *z = 0; // compilation error
// z = &a; // compilation error
// *z2 = 0; // compilation error
// z2 = &a; // compilation error
}
For example, is
int const x = 3;
valid code?
If so, does it mean the same as
const int x = 3;
?
They are both valid code and they are both equivalent. For a pointer type though they are both valid code but not equivalent.
Declares 2 ints which are constant:
int const x1 = 3;
const int x2 = 3;
Declares a pointer whose data cannot be changed through the pointer:
const int *p = &someInt;
Declares a pointer who cannot be changed to point to something else:
int * const p = &someInt;
Yes, they are the same. The rule in C++ is essentially that const applies to the type to its left. However, there's an exception that if you put it on the extreme left of the declaration, it applies to the first part of the type.
For example in int const * you have a pointer to a constant integer. In int * const you have a constant pointer to an integer. You can extrapolate this to pointer to pointers, and the English may get confusing but the principle is the same.
For another dicussion on the merits of doing one over the other, see my question on the subject. If you are curious why most folks use the exception, this FAQ entry of Stroustrup's may be helpful.
Yes, that is exactly the same. However, there is difference in pointers. I mean:
int a;
// these two are the same: pointed value mustn't be changed
// i.e. pointer to const value
const int * p1 = &a;
int const * p2 = &a;
// something else -- pointed value may be modified, but pointer cannot point
// anywhere else i.e. const pointer to value
int * const p3 = &a;
// ...and combination of the two above
// i.e. const pointer to const value
const int * const p4 = &a;
From "Effective C++" Item 21
char *p = "data"; //non-const pointer, non-const data
const char *p = "data"; //non-const pointer, const data
char * const p = "data"; //const pointer, non-const data
const char * const p = "data"; //const pointer, const data
const pointer: pointed value may be modified, but pointer cannot point
anywhere else
It is the same in meaning and validity.
As far as I know, const only get complex whenever it involves pointer.
int const * x;
int * const x;
are different.
int const * x;
const int * x;
are same.
I found that if always write const in right, it will becoming easier to read a complex pointer type, for fun.
For example:
// Just append const or pointer to
int x; // data
int const cx; // const data
int *px; // pointer to data
int const *pcx; //pointer to const data
int * const cpx; // const pointer to data
int const * const * * const cppcpcx; // const pointer to (pointer to (const pointer to const data))
I have an idea how to interpret (non)const pointers and data. Split it with *.
Data type
Star sign
Pointer type
Combine
Data
Pointer
int
*
p
int *p
non-const
non-const
const int
*
p
const int *p
const
non-const
int
*
const p
int *const p
non-const
const
const int
*
const p
const int *const p
const
const
// 1.
int x1 = 1;
int x2 = 2;
const int* p = &x1;
//*p = 3; // variable data is CAN NOT BE changed through pointer
p = &x2; // pointer CAN POINT to other variable
cout << *p << endl; // OUTPUT: 2
// 2.
int y1 = 1;
int y2 = 2;
int* const t = &y1;
*t = 3; // variable data is CAN BE changed through pointer
//t = &y2; // pointer CAN NOT POINT to other variable
cout << *t<<endl; // OUTPUT: 3