Const correctness: const char const * const GetName const (//stuff); - c++

Labelled as homework because this was a question on a midterm I wrote that I don't understand the answer to. I was asked to explain the purpose of each const in the following statement:
const char const * const GetName() const { return m_name; };
So, what is the explanation for each of these consts?

Take them from the right. The one before the ; tells the client this is a design level const i.e. it does not alter the state of the object. (Think of this as a read-only method.)
Okay, now the return value:
const char const *const
This is a constant pointer to okay ... here we go boom! You have an extra const -- a syntax error. The following are equivalent: const T or T const. If you take out a const you get a constant pointer to a constant characters. Does that help?

You have one more const than is syntactically allowed, that code would not compile. Remove the "const" after "char" and before the "*". Also, the last const must come before the function body. It helps to read things like this from right to left.
const char * const GetName() const { return m_name; };
You have a const function (i.e., the function does not alter the state of the class.), which returns a const pointer to a const char.

(1)const char (2)const * (3)const GetName() { return m_name; } (4)const;
The contents of char array is const. This is good when you return pointer of the object member. Since you give pointer to your member for 3rd party, you want to prevent it to be changed from outside.
This form is not used frequently and essentially same as (1)
Our pointer to char array is const, so you can not change where the pointer points too.
it qualifies the GetName() intself, meaning that the method thus not change the class it applied too. Thus it can be called for const object of this type only.
This form typically used as GetName(...) const.
As already mentioned in another answers the trick to "remember" it it read from right to left:
const T * - pointer to const T
T * const - const pointer to T

Edit: Looks like I incorrectly pasted the code into Comeau, or it was edited in the original answer to be correct. In either case I'm preserving the answer below as if the code were incorrect.
Comeau online compiler gives these results:
"ComeauTest.c", line 4: error: type
qualifier specified more than once
const char const * const GetName() {
return m_name; } const;
^
"ComeauTest.c", line 4: warning: type
qualifier on return type is
meaningless const char const * const
GetName() { return m_name; } const;
^
"ComeauTest.c", line 4: error:
declaration does not declare anything
const char const * const GetName() {
return m_name; } const;
What this means is that your statement is malformed.
const char const * const GetName() { return m_name; } const;
The first and second consts mean the same thing. You can't specify the same qualifier more than once so one of these would have to be removed for the code to compile. Both of these consts specify that the values pointed to by the pointer returned by GetName cannot be modified, making code like this invalid:
const char* name = c.GetName();
name[0] = 'a';
The third const specifies that the pointer returned by GetName() itself cannot be modified, but as Comeau points out, this doesn't accomplish anything on a return value because the return value is a copy of the pointer rather than the pointer itself, and can be assigned to a non-const pointer.
The fourth const is misplaced, it should be between GetName and the function body like this:
const char* GetName() const { return m.name; }
This const specifies that no members of the class will be modified during the execution of GetName. Assuming that GetName a member of the class Person, this code would be allowed:
const Person& p;
p.GetName();
Without this const, the above code would fail.

It is possible that you missed "*" symbol before second const keyword.
const char * const * const GetName() const { return m_name; };
So it means that the function returns constant pointer to constant pointer to constant character.

last const:
Function does not change the privates of the class
one after last const:
It's a constant pointer (i.e. the place it points to is constant)
second const:
The function returns a const char (i.e. the content of the char is constant)
First:
No idea?
So to be complete:
The function returns a constant pointer (always same location) to a constant char(always same content) and the function does not modify the state of the class.

const(1) char const(2) * const GetName() { return m_name; } const(3);
const char * const result = aaa.GetNAme();
3 - const method, not allowed to change members nor call any non-const methods.
1 - does not allow to modify inside the pointer, i.e. *result = ..
2 - does not allow to move the pointer, i.e. result = NULL

Given:
const char const * const GetName() const { return m_name; };
The first and second const are equivalent, but only one of them is allowed -- i.e. you can put const before or after the type (char in this case) but only one or the other, not both. Either, however, says that the characters pointed to by the pointer cannot be written to.
The const after the '*' means the pointer returned by the function cannot itself be modified. This is rarely seen on a return type -- what you're returning is a value, which can't be modified in any case (it's normally just assigned to some variable). This can, however, be meaningful in other contexts.
The third const is only allowed on a member function. It says that when this function is called, the this pointer that's received will be a T const * const rather than a T * const, so the member function can only modify static or mutable members of the object, and if it invokes other member functions, they must be const as well. There is, however, a caveat, that it can also cast away the const'ness, in which case it can modify what it sees fit (with the further caveat that if the object was originally defined as const, rather than just having a const pointer to a normal (non-const) object, the results will be undefined).

Related

Understanding char* - C++

I am writing a code in C++ right now, and I have a dilemma.
EDIT: I added the class relevant definition
_fullName is defined in the class as a private dm(char _fullName)
my class contains the getter method below:
char* getFullName() const { return this->_fullName; }
However, I had in the past cases in which I returned char* with const(const char*)
I can change the getter method to this one:
const char* getFullName() const { return this->_fullName; }
Both versions are compiling but I don't know how to choose.
I would take the second version, but I wonder Why even the version without the const is compiling? shouldn't it give an error when I remove the const keyword, because the function is a CONST member function and therefore the dms are const as well and cannot be returned without the const keyword???
This is the class relevant definition:
class Professional
{
private:
char* _ID;
char* _fullName;
int _age;
char* _profession;
}
First understand what const attached to a member function means. It determines the const-ness of the implicit this used for the member. Given this:
struct S
{
char value[10];
const char *mfn() const { return value; }
};
within the confines of mfn the implicit this is const S *. Furthermore, all references to members obtained therein are also const. In this case, that means value as an expression representation is const char (&)[10] before any further conversion are attached therein.
That's important.
In the correct posted example above there is an automatic conversion to temporary pointer, since const char(&)[10] converts to const char* without objection. However, the following will fail:
struct S
{
char value[10];
char *mfn() const { return value; }
};
The reason this will fail is simply because there is no conversion possible. value, remember, is const char (&)[10], and can only implicitly convert to const char*.
But how could it succeed? Well, consider this:
struct S
{
char *ptr;
char *mfn() const { return ptr; }
};
This will work. The reason is subtle, but obvious once you think about it. ptr is a char*. The attachment of const to this makes that char * const&, not const char *& (there is a difference; the former is a reference to a non-mutable pointer to mutable data, the latter is a reference to a mutable pointer to non-mutable data). Since return ptr is not mutating ptr (or anything else in the object), it is viable as a result.
In short, in your case it works because the pointer you are returning isn't via some implicit conversion from a const underlayment; it's just a value.
You have a few things going on here, in your example of the int num member this is not the same as a char * member.
lets expand your example a bit:
class Professional
{
int* func() const
{
return &myInt; // Fails because it returns a reference to a member variable
}
char* func() const
{
return &myChar; // Fails because it returns a reference to a member variable
}
int* func() const
{
return pInt; // ok because it returns a COPY of the member pointer
}
char* func() const
{
return pChar; // ok because it returns a COPY of the member pointer
}
int myInt;
char myChar;
int *pInt;
char *pChar;
Note: the two pointers getting returned by copy are ok. Its the pointers that are copies not the thing being pointed to. The memory that is pointed to is nothing to do with this class.
As to an answer to your question: there is a rule of thumb that is to apply const as much as possible - this helps to show other users your intent and gains benefits from compiler warnings / errors if a user tries to use your class in a way you did not intend. So in this case pass back a const char *.
Note: See this answer for more specific details here: What is the difference between const int*, const int * const, and int const *?

const char* classname::getname( ) const ? whats the meaning of first const keyword?

I know second constant keyword tells function is constant
class Person{
char *name;
int age;
public:
const char* GetName() const;
int GetAge() const;
};
the pointer that you assign the pointer returned by the function, points to a const char
const char* GetName() const;
The first occurence of the const keyword in the above statement is in the data type of the return value of the function GetName(), which is also a constant function.
This means that the value returned by GetName() will be:
of type char
a pointer
a const value
Since the return value will be const, GetName() will recieve a pointer to a constant char value. So if you have:
Person object;
const char* point = object.GetName();
*point will point to a constant char value.
As it has been explained above, it says const pointer. It will work only for const pointers.
const char * p = GetName(); //Compiled successfully
char * p = getName(); //compilation error... however you can remove using const_cast)
const char* reflect that char* is constant. Therefore following line will give error:--
*p = 'c';
However P is not constant here. So you can write like :--
char ch;
p = &ch;
Usually when function returns the value, we are concerned about value (like it should not be modified). I hope it will help.
It means that the function returns pointer to a constant char. Following will be a goodread for usage of const keyword in C++.
http://www.cprogramming.com/tutorial/const_correctness.html

C++ Difference between const positioning

I'm struggling to get my head around the differences between the various places you can put 'const' on a function declaration in c++.
What is the difference between const at the beginning:
const int MyClass::showName(string id){
...
}
And const at the end like:
int MyClass::showName(string id) const{
...
}
Also, what is the result of having const both at the beginning and at the end like this:
const int MyClass::showName(string id) const{
...
}
const int MyClass::showName(string id) returns a const int object. So the calling code can not change the returned int. If the calling code is like const int a = m.showName("id"); a = 10; then it will be marked as a compiler error. However, as noted by #David Heffernan below, since the integer is returned by copy the calling code is not obliged to use const int. It can very well declare int as the return type and modify it. Since the object is returned by copy, it doesn't make much sense to declare the return type as const int.
int MyClass::showName(string id) const tells that the method showName is a const member function. A const member function is the one which does not modify any member variables of the class (unless they are marked as mutable). So if you have member variable int m_a in class MyClass and if you try to do m_a = 10; inside showName you will get a compiler error.
Third is the combination of the above two cases.
The const attached to the return value applies to the return value. Since the return value is copied it's a pointless declaration and it makes no difference whether or not you include it.
The const after the parameter list means that the function does not modify any state of the object that is not marked as mutable. This is a const member function and if you have a const object the compiler will not allow you to call non-const member functions on a const object.
There is no interaction between these two uses of const - they are completely independent constructs
The difference is that the const applies to different things.
This says that showName returns a constant int value -- one that is immutable. Of course since the int is returned by value the presence of const here does not play any role.
const int MyClass::showName(string id)
And this says that showName does not modify the observable state of MyClass (technically: it does not modify any member that is not declared mutable), and therefore you are allowed to call it on a value of type const MyClass.
int MyClass::showName(string id) const
If you use both consts then both of the above apply.
Questions like this tend to strengthen my resolve to follow the advice of Dan Saks as outlined in this "Conversations with a Guru" article: http://www.drdobbs.com/conversationsa-midsummer-nights-madness/184403835 .
In particular it deals with how the placement of const changes things. (*) I realize that I am extremely unlikely to convert anyone from writing const int ... to int const ..., but that said, there is one reason I prefer to do the latter.
(*) incuding a note that swapping the const with the type declaration at the very start is the one change that has no effect.
It makes for very easy readability, because for any instance of the word
const in a declaration, everything to the left of it is the type of what is const, and everything to the right is what actually is const.
Consider a declaration like:
int const * * const pointerToPointer;
The first const states that the integers at the end of the pointer chain are const, and they are to be found at * * const pointerToPointer. Meanwhile the second one states that an object of type pointer to pointer to const int is also const and that this object is pointerToPointer.
In the OP's case:
int const MyClass::showName(string id){
...
}
The type of what is const is int, and what is const is the return value from the function.
Meanwhile:
int MyClass::showName(string id) const {
...
}
Here the type of what is const is function(string) returning int, and what is const is the function itself, i.e. the function body.

const - Shouldn't it not change

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.

Why does this const member function allow a member variable to be modified?

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.