So I am learning C++ right now, and I just started to get into Pointers, and I thought I would understand the semantics pretty well till iI saw this in one of the recommended solutions to an exercise int the Book I am learning with:
const char* sa = * ( static_cast < const char* const* > (a));
I understand everything aside the const* in the Type Parameter. Why is it there, what does it do?
EDIT: corrected unclear formulation
* in a type means that the type is a pointer to the type on the left side of the asterisk.
const in a type means that the type to the left of const is constant. For an object, const means that the value may not be modified. For a reference, const means that the object may not be modified through the reference.
char is a type that represents an integer encoded narrow character object.
const char is a const char.
const char* is a pointer to a const char.
const char* const is a const pointer to a const char.
const char* const* is a pointer to a const char* const.
Note that the pointer is indirected:
* ( static_cast < const char* const* > (a));
^ indirection operator
When a pointer is indirected, the result is a reference (lvalue) to the pointed object. If a const char* were indirected, the resulting lvalue would have the type const char. Clearly such lvalue couldn't be used to initialize the object const char* sa.
When a const char* const* is indirected, the result will be a reference (lvalue) to an object of type const char* const. Such value can be used to initialize const char* sa.
A simpler example without casts:
const char c; // c cannot be modified
const char* const a = &c; // a points to charcter object c
// a cannot be modified
const char* sa = *a; // sa points to a as well
sa = nullptr; // sa can be modified; it no longer points to a
Related
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.
In the following piece of code, to calculate strlen,
int s(const char* str)
{
int count=0;
while(*str++) count++;
return count;
}
You can see that the argument str is const. But, the compiler does not complain when I do a str++. My question is
When passing pointers as arguments to a C function, if is is qualified with const, How can I still perform pointer arithmetic on it? What is const in the above function?
const char* str;
means a non-const pointer to a const data.
char* const str;
means a const pointer to a non-const data.
const char* const str;
means a const pointer to a const data.
The reason for this is that in C++ the variable type declarations are parsed from right to left, which results in that the word "const" always defines the constness of the thing that it's closest to.
It's not declaring the pointer const, it's declaring the thing pointed to as const. Try this:
int s(const char* const str)
With this declaration, you should get a compile error when you modify str.
const char * ch; // non-const pointer to const data
char * const ch; // const pointer to non-constant data.
const char * const ch; // const pointer to const data
Note:
Also
const char * ch;
equals to
char const * ch;
The pointer points to a const char, a read-only character array.
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.
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