C++: Strange behavior of pointer data member in const context
The const
qualifier on a method supposed to protect the data member from overwriting by mistake. If you have a data member which is a pointer then only the pointer is defended, the pointed value is not. Is it a flaw in the design of C++ or is there something fundamental thing it serves?
Here is a code which demonstrates the situation. Before reporting irrelevant bugs and style problems, please consider that its sole purpose is to demonstrate the above situation and to be short and straightforward in that.
#include <cstdio>
#include <cstdlib>
#include <cstring>
class Cat
{
public:
Cat(char const *name)
: _name(strdup(name))
{ }
~Cat(){ free(_name); }
void SetName(char const *name)
{
free(_name);
_name = strdup(name);
}
char const* GetName() const
{
_name[0] = 'P';
return _name;
}
private:
char *_name;
};
int main()
{
Cat c("lost+found");
c.SetName("Molly");
printf("%s\n",c.GetName());
return 0;
}
Compilation went without warnings an开发者_StackOverflowd errors with the following command:
g++ -W -Wall -Wextra -pedantic -Os pmc.cpp -o pmc
The output of the resulting program was Polly
.
UPDATE Using pedantic char const *
instead of traditional const char *
The fundamental thing served here is simply clarity. The pointer is a member of the class, its pointee is not: It is neither automatically destructed when the class is nor automatically constructed. It might be a wholly different object, so it should not necessarily be const when the class becomes const.
You are desiring something like std::string here, that is, additional semantics for the pointer - for example the guarantee that its contents will not change outside of your class.
The const qualifier on a method supposed to protect the data member from overwriting by mistake. If you have a data member which is a pointer then only the pointer is defended, the pointed value is not.
You have a mistaken perception of the purpose of the const
qualifier. It serves three purposes:
- A const-qualified instance of some class can only call the const-qualified member functions of that class. Calls to member functions that are not const-qualified are forbidden in the case of a const-qualified instance.
- A const-qualified member function cannot change the direct contents of the instance. Contents that point to data external to the instance are not part of the direct contents of the instance; they simply are not protected by the
const
qualifier. - A huge avenue of optimizations become available to the compiler based on the above.
The const
qualifier does not protect you as the author of some class from shooting yourself in your foot (or higher). What it does do is to protect you as the author of some class against someone else doing damage to your class and it allows the compiler to go to town with several optimizations that are not available in a non-const setting.
In the const
member function, the type of _name
becomes char * const
which means it is the pointer which is const, not the data which the pointer points to.
You seem to think that _name
becomes const char*
. No, the const
applies on the pointer
, not on the data it points to. So _name
has to become char * const
.
To minimize this confusion, I prefer the syntax T const
over const T
even though both are exactly same. Because if T
is char*
, then T const
would become char * const
, whereas const T
would become const char*
. While the former helps understanding, the latter complicates.
精彩评论