Question

It maybe seems to be a silly question but i really need to clarify this:

Will this bring any danger to my program?

Is the const_cast even needed?

If i change the input pointers values in place will it work safely with std::string or will it create undefined behaviour?

So far the only concern is that this could affect the string "some_text" whenever I modify the input pointer and makes it unusable.

std::string some_text = "Text with some input";

char * input = const_cast<char*>(some_text.c_str());

Thanks for giving me some hints, i would like to avoid the shoot in my own foot

Was it helpful?

Solution

As an example of evil behavior: the interaction with gcc's Copy On Write implementation.

#include <string>
#include <iostream>

int main() {
    std::string const original = "Hello, World!";
    std::string copy = original;

    char* c = const_cast<char*>(copy.c_str());
    c[0] = 'J';

    std::cout << original << "\n";
}

In action at ideone.

Jello, World!

The issue ? As the name implies, gcc's implementation of std::string uses a ref-counted shared buffer under the cover. When a string is modified, the implementation will neatly check if the buffer is shared at the moment, and if it is, copy it before modifying it, ensuring that other strings sharing this buffer are not affected by the new write (thus the name, copy on write).

Now, with your evil program, you access the shared buffer via a const-method (promising not to modify anything), but you do modify it!

Note that with MSVC's implementation, which does not use Copy On Write, the behavior would be different ("Hello, World!" would be correctly printed).

This is exactly the essence of Undefined Behavior.

OTHER TIPS

To modify an inherently const object by casting away its constness using const_cast is an Undefined Behavior.

string::c_str() returns a const char *, i.e: a pointer to a constant c-style string. Technically, modifying this will result in Undefined Behavior.

Note, that the use of const_cast is when you have a const pointer to a non const data and you wish to modify the non-constant data.

Simply casting will not bring forth an undefined behavior. Modifying the data pointed at, however, will. (Also see ISO 14882:98 5.2.7-7).

If you want a pointer to modifiable data, you can have a

std::vector<char> wtf(str.begin(), str.end());
char* lol= &wtf[0];

The std::string manages it's own memory internally, which is why it returns a pointer to that memory directly as it does with the c_str() function. It makes sure it's constant so that your compiler will warn you if you try to do modifiy it.

Using const_cast in that way literally casts away such safety and is only an arguably acceptable practice if you are absolutely sure that memory will not be modified.

If you can't guarantee this then you must copy the string and use the copy.; it's certainly a lot safer to do this in any event (you can use strcpy).

See the C++ reference website:

const char* c_str ( ) const;

"Generates a null-terminated sequence of characters (c-string) with the same content as the string object and returns it as a pointer to an array of characters.

A terminating null character is automatically appended.

The returned array points to an internal location with the required storage space for this sequence of characters plus its terminating null-character, but the values in this array should not be modified in the program and are only guaranteed to remain unchanged until the next call to a non-constant member function of the string object."

Yes, it will bring danger, because

  1. input points to whatever c_str happens to be right now, but if some_text ever changes or goes away, you'll be left with a pointer that points to garbage. The value of c_str is guaranteed to be valid only as long as the string doesn't change. And even, formally, only if you don't call c_str() on other strings too.
  2. Why do you need to cast away the const? You're not planning on writing to *input, are you? That is a no-no!

This is a very bad thing to do. Check out what std::string::c_str() does and agree with me.

Second, consider why you want a non-const access to the internals of the std::string. Apparently you want to modify the contents, because otherwise you would use a const char pointer. Also you are concerned that you don't want to change the original string. Why not write

std::string input( some_text );

Then you have a std::string that you can mess with without affecting the original, and you have std::string functionality instead of having to work with a raw C++ pointer...

Another spin on this is that it makes code extremely difficult to maintain. Case in point: a few years ago I had to refactor some code containing long functions. The author had written the function signatures to accept const parameters but then was const_casting them within the function to remove the constness. This broke the implied guarantee given by the function and made it very difficult to know whether the parameter has changed or not within the rest of the body of the code.

In short, if you have control over the string and you think you'll need to change it, make it non-const in the first place. If you don't then you'll have to take a copy and work with that.

it is UB. For example, you can do something like this this:

size_t const size = (sizeof(int) == 4 ? 1024 : 2048);
int arr[size];

without any cast and the comiler will not report an error. But this code is illegal. The morale is that you need consider action each time.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top