0

I have written a small problem for checking the behavior of const_cast on const data member.

using namespace std;


     class myString{
         public:
                 myString(char * str)
                 {
                         p=str;
                 }
                 const char * getString(){
                         return p;
                 }
         private:
                 const char *p;
 } ;


int main()
{
        char *p=(char*)malloc(8);
        cin>>p;
        myString *m= new myString(p);
        char *s =const_cast<char*>(m->getString());
        s[6]='y';
        cout<<s<<endl;
        return 0;
}

After running this program I give the out as "yogendra" (a 8 letter string). and i got the output as "yogendya" Now my doubt. Through const_cast<> we can override the behavior of the data member itself as here the string is const char* still after casting i can modify it.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
dead programmer
  • 4,223
  • 9
  • 46
  • 77
  • This is one reason why you normally should write your code so you won't need any const_cast. The presence of const_cast in code many times shows a problem with the design of the application (though there are valid uses for it as well, as are times when it can't be avoided). – utnapistim Mar 26 '13 at 11:44
  • @PeterWood: Apart from not allocating enough memory for the input, where is the undefined behaviour here? Modifying a `const` object would be, but there are no `const` objects in this example. – Mike Seymour Mar 26 '13 at 11:46
  • @PeterWood link to standard? AFAIK in C++ casting away const is UD only for multithreaded environment or immutable data such as literals. Adding const manually and then casting it away should be no-op (though hardly reasonable) – Mihails Strasuns Mar 26 '13 at 11:47
  • @MikeSeymour Mea culpa – Peter Wood Mar 26 '13 at 12:49

3 Answers3

5

You've described exactly what const_cast is for - it allows you to removed the constness from something and modify it. It's up to you not to abuse that power. :-)

(In your case this doesn't apply, but note that you can cause crashes by using const_cast - for example:

const char *c = "Hello";
char *s = const_cast<char*>(c);
s[0] = 'h';

could crash because the compiler can put the string literal into read-only memory.)

RichieHindle
  • 272,464
  • 47
  • 358
  • 399
  • It is worth noting that this is only C++ cast that actually allows to avoid const, and it is its single purpose. Not even reinterpret_cast will allow it. – Mihails Strasuns Mar 26 '13 at 11:49
1

yes, you can use const_cast<> this way and it will not be an undefined behaviour since object pointed to by const char* in your class is indeed non-const of type char*. but be careful:. C++ standard. §7.1.​5.1/4 says

Except that any class member declared mutable (7.1.1) can be modified, any attempt to modify a const object during its lifetime (3.8) results in undefined behavior

safe use of const_cast is to i.e. cast const from const reference to a non-const object: when there is non const object and you have const ref to it, you can cast const from this safely

4pie0
  • 29,204
  • 9
  • 82
  • 118
  • 1
    There are no const objects in this example, so no undefined behaviour (except that caused by not allocating enough memory for the input). – Mike Seymour Mar 26 '13 at 11:51
  • 1
    getString returns const char* – 4pie0 Mar 26 '13 at 11:52
  • Indeed; it returns a const pointer to a non-const object. The object itself is the array allocated by `malloc`, which is not const. – Mike Seymour Mar 26 '13 at 11:53
  • so this is exactly this safe example, it is const casted from const char* pointer to char object, right? – 4pie0 Mar 26 '13 at 11:55
  • @MikeSeymour: Are you sure the returned value is *"const pointer to a non-const object"*, `const char *` is the returned type. – Alok Save Mar 26 '13 at 11:57
  • exactly, I am keen to believe in both ideas now ; ( – 4pie0 Mar 26 '13 at 11:58
  • but isn't this a const char* to char object? – 4pie0 Mar 26 '13 at 11:59
  • @AlokSave: Sorry if I wasn't clear enough. The returned type is indeed pointer-to-const (which I loosely called "const pointer"); but the object pointed to is not const, so can be modified using `const_cast`. – Mike Seymour Mar 26 '13 at 12:00
  • 1
    @MikeSeymour: :) Thanks for the clarifying that bit. The inherent object, one returned by `malloc` is not const. The example treats this returned object as an const object by allowing a *pointer to const* to this object, Further this pointer is casted to remove the constness. Since the original object was not const to begin with there is no UB. However, if the original was indeed an const object this would be a UB. So the key is *inherent* qualifier of the original object not the qualifier on the intermediate pointer. – Alok Save Mar 26 '13 at 12:09
0

If you say

char *s =const_cast<char*>(m->getString());

then you essentially remove the "const" from the pointer, and you declare your s to be a pointer to char, and it's a writable string. So the next line

s[6]='y';

is perfectly fine. To keep the const you ought to declare s as a const pointer

const char *s = m->getString();

in which case you won't be able to overwrite the constant string (error: assignment of read-only location). I assume that is what you want? The const_cast will simply add/remove the const and in your case, remove it.

Jens
  • 8,423
  • 9
  • 58
  • 78
  • Thanks for the nice explanation but ..What if I make change as myString *m=new myString("yogendra"); here i have passed a const char *, when I run this code I got a segmentation fault. – dead programmer Mar 26 '13 at 11:53
  • @YSBhai: In that case, you're trying to modify a `const` object (a string literal). Doing that gives undefined behaviour; in your case, the object must have been placed in read-only memory so that modification causes a fault. – Mike Seymour Mar 26 '13 at 11:55
  • @MikeSeymour: You beat me to it :) – Jens Mar 26 '13 at 11:57
  • @YSBhai: Every string literal, like in your case the "yogendra", is placed in read-only memory by the compiler. Your myString class keeps the address of that read-only string in `p`, and trying to write to it using `s[6]='y'` will cause the segmentation fault. To get around that, create a copy of the string literal inside your myString class to ensure it's writable. Or don't write to it :) – Jens Mar 26 '13 at 12:00