In running this C++ code, I expected the output to be Abc, but, it was FFF, why is that? Isn't name pointing to a constant char?
#include <iostream>
int main()
{
const char* name = "Abc";
name = "FFF";
std::cout<<name<<std::endl;
return 0;
}
Yes, it's pointing to a const char as you say, but it is not a constant pointer. You are changing what you are pointing to, not the contents of what you are pointing to. In other words, the memory holding "Abc" still holds the characters "Abc" after you reassign the pointer.
For a constant pointer, you want const char* const name = "Abc";. In this case, it won't compile since you can't change what the pointer points to.
In general, with const and pointers in C++, you can read the type name from right-to-left to get a feel for what is going on. For example, in the const char* const case, you can read this as "a constant pointer to a character constant". A little weird, but it works.
const char* name = "Abc"; -> Non const pointer-> name, but data (Abc) is constant
name = "FFF" -> changing pointer(name) to point to FFF.
char *p = "Hello"; // non-const pointer,
// non-const data
const char *p = "Hello"; // non-const pointer,
// const data
char * const p = "Hello"; // const pointer,
// non-const data
const char * const p = "Hello"; // const pointer,
// const data
With const char* name = "Abc"; you are telling compiler you will not change the contents of "Abc" using name. However, you are free to change the pointer to point to a different memory location. See this FAQ for details.
It is a known issue with const and English speakers.
The syntax allows both:
const T
T const
and both have the same meaning.
However it becomes complicated once you throw a pointer in the mix:
const T* should be read (const T)*
T const* should be read (T const)*
T* const should be read (T*) const
For that reason I am an adept of always using const on the immediate right of the object. This is more consistent.
Note that the same issue can be found with typedef, let's define typedef T* pointer:
const pointer means T* const, not const T* (as a macro would imply)
pointer const means T* const, like the textual replacement
If you take the habit of putting the const after the name, and not before like an adjective in English, then you won't fall into those traps.
in deed the most correct syntax is
char const * pName;
because const keyword apply namely to the part on the left hand side.
if you want a const poitner to a const char you would write it:
char const * const pName;
and a const pointer to an int;
int * const pInt;
PS: but I still write the const at the begining of the line whenever I can, an anchored habbit ;-)
const char* name = "Abc";
Actually this means, name is a pointer to the const data. Means, it's the data which is const, not the pointer itself. So it's perfectly valid if you write:
name = "FFF"; //ok : changing the pointer
However, the following will not compile:
char * const name = "Abc"; //const pointer to the non-const data!
name = "FFF"; //error: trying to change the pointer itself!
See the compiler error:
prog.cpp:5: error: assignment of
read-only variable ‘name’
See yourself here : http://www.ideone.com/KyNXx
When you declare a variable as
const T* ptr = /*...*/
You are declaring a pointer saying that the object being pointed at, not the pointer, must not change. In other words, it's a "pointer to a T that's const."
If you want to make it impossible to reassign the pointer, you can write
T* const ptr = /*...*/
This is now an immutable pointer to a T, which can be modified.
You can combine these together like this:
const T* const ptr = /*...*/
To get an immutable pointer to an immutable T.
As a fun hint, you can usually determine what parts of a pointer/pointed pair can be modified by reading the type right-to-left. Try that out on the above and see what you get.
First, const is only checked at compilation time. If it compiles, all operations will be done normally at runtime.
In your example, const applies to the content pointed by name. So you are allowed to change the pointer, but not the content.
strcpy(name, "FFF");
would be refused, but not changing the pointer like you did.
The literal strings "Abc" and "FFF" are constant, but name is a variable (pointer to constant data). You have simply changed the variable to point to different constant data.
Moreover while in this case the data was necessarily constant, a pointer to constant data only means that the data cannot be modified by dereferencing that pointer, the data might also be modified directly or through a different pointer. E.g.
int i = 0 ;
const int* p = &i ;
i++ ; // valid
(*p)++ // error.
Related
I know this is probably a trivial question. What is the logic behind not being able to set a const pointer after its declaration? It's not as if allocating memory will change the starting address which is what the const refers to. So why can't this...
int* const p;
p = new int [10];
... be done... which also prohibits the passing of a const pointer into a function?
This is the entire purpose of const.
const stands for "constant", and means the object cannot be assigned to.
If you want the pointer to be a variable, don't make it const.
I suspect you were expecting your assignment to be allowed because it was the first ever assignment to that object. You were wrong! This is the purpose of initialisation, which you are not presently using.
I'm guessing you meant to write:
int* const p = new int[10];
But I worry that you have more fundamental misconceptions here. For example:
It's not as if allocating memory will change the starting address
Yes, it absolutely, completely will.
When your p comes into existence, it has an unspecified value. Its value is not a "starting address" that you can use.
Then you assign to it (though you ought to have initialised instead). It takes on the value equals to the pointer returned by new. That pointer has no relationship to anything previous in your code.
Allocating memory does change the address. For instance if we have
int * foo;
foo = new int[bar];
foo is uninitialized and has a garbage value. Then foo = new int[bar]; assigns to foo a new address that is the start of a block of bar ints.
Now when you have
int* const p;
The pointer is const so we cannot change it after it is initialized.
Short version
The way you are defining the pointer means that it is const for itself, so you cannot reassign it and you have actually to assign it along with its declaration.
Here more details about the const keyword, even though it is not specifically oriented to the use with the pointers.
Please even note that the following code should not compile for you are not assigning a value to the const pointer p:
int main() {
int * const p;
}
The same is true for the following one:
int main() {
int const i;
}
It doesn't depend on the fact that you are dealing with a pointer, instead it's how the const keyword actually works and should/can be used.
More details about const and pointers
Anyway, I didn't see your whole code and it looks to me that your intent is not to have a const pointer, instead in your case it could help having a pointer to const (but it mainly depends on your problem, so I can be wrong).
How to define them depends on your purposes, of course.
You can either define it as a const pointer or a pointer to a const value, the means of which are slightly different (of course, you can also define a pointer as a const pointer to a const value, that is an easily deducible consequence of the others above mentioned).
The first one indicates that the pointer itself cannot be reassigned, thus you have to assign it during the declaration and that's all.
The second one instead define a pointer that is reassignable, but you can assign it only addresses of const variables of the given type (or better, even if they are defined as non const, they will be treated as const when accessed through that pointer, with all the limitations of the case).
It follows a brief example of the types of const pointer and pointer to const above mentioned:
int main() {
int i;
// pointer to const int
int const *icp;
// const pointer to int
int * const cip = &i;
// const pointer to const int
int const * const cicp = &i;
// this one can be reassigned, of course
icp = &i;
}
Note also that int const and const int are interchangeable, so the declarations below are equivalent:
int const *p;
const int *p;
Obviously, this is not an exhaustive list. I've only tried to give you more details about how the const keyword can be used while defining a pointer and which are the intended means of those declarations.
int* const p;
declares p to be a pointer which cannot be changed, i.e. you cannot change where it points to once it is initialized. However, you can change the values it points to since the object type it points to is int.
int* const p = new int [10];
p = new int[20]; // Not OK
p[0] = 100; // OK
Contrast that with
int const* p = new int [10];
p = new int[20]; // OK. You can change where the pointer points to.
p[0] = 100; // Not OK. You cannot change the value of what p points to.
I just wondered what's the difference between having a constructor with const char* c or char* const c as a parameter?
If I swap char* and const in header and source file it isn't a problem but when I mix them it won't compile, saying there is no such overloaded constructor.
When I use my own class for a copy constructor the compiler doesn't seem to bother if I have MyClass const &other and const MyClass &other mixed..
Can anyone enlighten me please? :)
This record const char *c declares pointer c that points to an object of type const char. That is using this pointer you may not change the object that refered to by the pointer.
This record char * const c declares const pointer c that points to a non-const object of type char. You may not change the pointer itself but you may change the object refered to by the pointer.
There is a difference between declaring pointers and references. Though there is used term "constant reference" strictly speaking references themselves may not be constant. According to the C++ grammar
ptr-operator:
* attribute-specifier-seqopt cv-qualifier-seq
& attribute-specifier-seqopt
references do not contain cv-qualifier-seq. So for example this record
Airplane & const other
will be incorrect and the compiler shall issue an error.
As for these records
const Airplane & other
Airplane const & other
then they are equivalent the same way as equivalent the recirds below
const char *c
char const *c
Think of the * as a "fence". What's before it in the declaration defines the type that the pointer refers to. What's after the * defines the pointer itself. For this case, it's easiest to read things backwards (translating * as "pointer to"), so char const *t is read (from back to front) as: "t is a pointer to a const char". Likewise, char *const t is read as: "t is a const pointer to a char."
char *const means the pointer itself is const (can't be modified), but the char(s) it points at can be modified.
char const * or const char * are equivalent to each other. Both mean the pointer itself can be modified, but what it points at cannot.
Substituting a different type for char doesn't change that basic idea.
The same is true with a reference: const T & means a reference to a const T, so you can't modify the T that it refers to. In the case of a reference, you can't modify the reference itself to refer to a different object, so T & const doesn't make any real sense (and isn't allowed).
const applies to the type to its left (or to its right if there is nothing on its left), so const char * and char const * are the same and mean that the characters cannot change, but the pointer can, whereas char * const means that the characters can change but the pointer cannot
The order in which const and char* are written actually make a difference. If you have const char* in your header but char* const in your source file, you will get an error because the compiler won't regard these as the same.
const char* p means that p points to a char that is constant. We can alter where p points to, but we can never alter the contents stored at p.
char* const p means that p is a constant pointer and is pointing to a char. We can alter the contents stored at p, but we cannot alter where p points to.
const char* const p means that p is a constant pointer to a constant char. We cannot alter where p points to nor can we alter the contents at p. Hope this is helpful!
I'd like to know what's the difference between const ref and const pointer in c++.
When I declare on something to be const ref, can I change it's VALUE?
or the const goes on the object?
Because I know that const pointer means you cannot change the POINTER but you can change the VALUE it points to.
for example:
const char& a; // ?
const char* a; // pointer is const
Fred const& x;
It means x aliases a Fred object, but x can't be used to change that Fred object.
Fred const* p;
Fred const* p means "p points to a constant Fred": the Fred object can't be changed via p.
Fred* const p;
Fred* const p means "p is a const pointer to a Fred": you can't change the pointer p, but you can change the Fred object via p.
It's possible to combine the last to to get:
Fred const* const p;
Fred const* const p means "p is a constant pointer to a constant Fred": you can't change the pointer p itself, nor can you change the Fred object via p.
For more on this visit this link.
const char* a; // pointer is const
Wrong, this is a pointer to a constant. This:
char* const a; // pointer is const
is a constant pointer.
I prefer to write these like this: char const * a vs. char * const a.
This allows you to read from right to left: char const * a is: a is a pointer to a constant char, and char * const a is: a is a constant pointer to a char. And if I read other code, I just remember that const char* a = char const* a.
To answer the other part of your question:
When I declare on something to be const ref, can I change it's VALUE?
People misuse the term const ref to actually mean reference to a constant (since a constant reference makes no sense). So, const ref const char& a means that you cannot change the value. But if you actually mean you want a constant reference, char& const a then you can change the value and the const part makes no difference.
For pointers, const char* a means you cannot change the value a points to. Compare this to char* const a which means you cannot change the pointer, but you can change the value a points to.
I often see the following function declaration:
some_func(const unsigned char * const buffer)
{
}
Any idea why the const is repeated before the pointer name?
Thanks.
The first const says that the data pointed to is constant and may not be changed whereas the second const says that the pointer itself may not be changed:
char my_char = 'z';
const char* a = &my_char;
char* const b = &my_char;
const char* const c = &my_char;
a = &other_char; //fine
*a = 'c'; //error
b = &other_char; //error
*b = 'c'; //fine
c = &other_char; //error
*c = 'c'; //error
type declarations should(?) be read RTL. const modifies the thing on its left, but the rule is complicated by the fact that you can write both const T and T const (they mean the same thing).
T * const is a constant pointer to mutable T
T & const would be constant reference to mutable T, except references are constant by definition
T const * is a mutable pointer to constant T
T const & is a reference to constant T
T const * const is constant pointer to constant T
It's a constant pointer to a constant unsigned char. You can't change the pointer nor the thing it points to.
In a declaration like const * const T, the first const (before the *) means that what the pointer points at is const (i.e. it's a pointer to a const T). The const after the * means that the pointer itself is const (i.e. can't be modified to point at anything else).
You can read the declaration from the object being declared outward, so const unsigned char * const buffer is read as: "buffer is a const pointer to a const unsigned char" (this is why const should always being placed after what it modifies--with it before, you have to rearrange things to make the sentence--with it declared as unsigned char const * const buffer, translation to English is simple and straighforward (or perhaps "straightbackward", since you actually read from right to left in this case).
assuming const unsigned char * const
Everyone is correct that its a const pointer to a const unsigned char.
C++ types read mostly right to left unless there are any modifiers on the far left then these read left to right.
This makes it a const pointer to a const value, rather than a mutable pointer to a const value or a const pointer to a mutable value.
const * unsigned char const buffer means that you cannot modify the pointer buffer nor the memory that buffer points to.
A couple of articles to help you understand const correctness in C++:
Wikipedia
Possibility.com
class String
{
private:
char* rep;
public:
String (const char*);
void toUpper() const;
};
String :: String (const char* s)
{
rep = new char [strlen(s)+1];
strcpy (rep, s);
}
void String :: toUpper () const
{
for (int i = 0; rep [i]; i++)
rep[i] = toupper(rep[i]);
}
int main ()
{
const String lower ("lower");
lower.toUpper();
cout << lower << endl;
return 0;
}
A const member function, is a member function that does not mutate its member variables.
const on a member function does not imply const char *. Which would mean that you can't change the data in the address the pointer holds.
Your example does not mutate the member variables themselves.
A const on a member function, will ensure that you treat all of your member variables as const.
That means if you have:
int x;
char c;
char *p;
Then you will have:
const int x;
const char c;
char * const p; //<-- means you cannot change what p points to, but you can change the data p points to
There are 2 types of const pointers. A const member function uses the one I've listed above.
A way to get the error you want:
Try changing:
char * rep;
to:
char rep[1024];
And remove this line:
rep = new char [strlen(s)+1];
It will throw the error you are expecting (can't modify members because of const keyword)
Because there is only 1 type of const array. And that means you cannot modify any of its data.
Now the whole system is actually broken with the following example:
class String
{
private:
char rep2[1024];
char* rep;
...
String :: String (const char* s)
{
rep = rep2;
strcpy (rep, s);
}
So the lesson to learn here is that the const keyword on member functions does not ensure that your object will not change at all.
It only ensures that each member variable will be treated as const. And for pointers, there is a big diff between const char * and char * const.
Most of the time a const member function will mean that the member function will not modify the object itself, but this is not always the case, as the above example shows.
The reason is that you don't change rep. If you would, you would find rep = ...; somewhere in your code. This is the difference between
char*const rep;
and
const char* rep;
In your case, the first one is done if you execute a const member-function: The pointer is const. So, you won't be able to reset the pointer. But you will very well be able to change what the pointer points to.
Now, remember rep[i] = ...; is the same as *(rep + i) = ...;. Thus, what you change is not the pointer, but what the pointer points to. You are allowed, since the pointer is not of the second case type.
Solution
The const meaning you are looking at is physical constness. However, a const member-function means your object is logical const. If a change to some content will change the logical constness of your object, for example if it changes some static variable that your object depends upon, your compiler cannot know that your class now has another logical value. And neither it can know that the logical value changes dependent on what a pointer points to: The compiler doesn't try to check logical constness in a const member function, since it cannot know what those member variables mean. This stuff is termed const-correctness.
Use an object that is not just a reference or a pointer: A const member function will make that object const, and will disallow you to change its content. std::string, as proposed by some, or an array of characters (note that an array will disallow you changing its content, as opposed to just a pointer), would be an appropriate choice.
2.
toUpper() does not change the pointer (which belongs to the class). It only changes the data which rep points to (that do not belong to the class).
However, 'const' is a sort of warranty for the users of your class: if a method is declared const, who uses an instance of your class can expect it won't change when calling the method. My point is, if toUpper() changes the state of a string, don't declare it const, whether C++ allows it or not.
The const qualifier means it will not change any members of the class.
In this case rep is the only member of the class and I see no attempt to modify this member. Anything pointed at or referenced outside the class is not considered as part of the class.
A solution to this problem would be to replace the char* with a std::string.
Then you would only be able to call const members of std::string from within toUpper()
For example (use std::string)
class String
{
std::string rep;
void toUpper() const
{
for (int i = 0; rep [i]; i++)
rep[i] = toupper(rep[i]);
// Can only use const member functions on rep.
// So here we use 'char const& std::string::operator[](size_t) const'
// There is a non const version but we are not allowed to use it
// because this method is const.
// So the return type is 'char const&'
// This can be used in the call to toupper()
// But not on the lhs of the assignemnt statement
}
}
You cannot change the value of something declared as
const char* rep;
or
const char* const rep;
Unfortunately, declaring your member const turns into rep into
char* const rep;
which means, you cannot change the acutal address, but you can change the contents, whereas you cannot change the value.
To make const memebrs respect keep your buffer const, you will need to make rep and array of characters or a string object rather than a character pointer.