Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Consider the following example:

int main()
{
    string x = "hello";
    //copy constructor has been called here.
    string y(x);
    //c_str return const char*, but this usage is quite popular.
    char* temp = (char*)y.c_str();

    temp[0] = 'p';

    cout << "x = " << x << endl;
    cout << "y = " << y << endl;

    cin >> x;
    return 0;
}

Run it on visual studio compiler and on g++. When I did so, I got two different results.
in g++:

x = pello  
y = pello

In visual studio 2010:

x = hello  
y = pello

The reason for the diff is most likely that g++ std::string implementation uses COW (copy on write) techniques and visual studio does not.

Now the C++ standard (page 616 table 64) states with regards to string copy constructor

basic_string(const basic_string& str):

effects:
data() should "points at the ?rst element of an allocated copy of the array whose ?rst element is pointed at by str.data()"

Meaning COW is not allowed (at least to my understanding).
How can that be?
Does g++ meets std::string C++11 requirements?

Before C++11 this did not pose a big problem since c_str didn't return a pointer to the actual data the string object holds, so changing it didn't matter. But after the change this combination of COW + returning the actual pointer can and breaks old applications (applications that deserve it for bad coding but nevertheless).

Do you agree with me? If yes, can something be done? Does anyone have an idea about how to go at it in a very big old code environments (a clockwork rule to catch this would be nice).

Note that even without casting the constness away, one might cause invalidation of a pointer by calling c_str, saving the pointer and then calling non-const method (which will cause write).
Another example without casting the constness away:

int main()
{
    string x = "hello";
    //copy constructor has been called here.
    string y(x);

    //y[0] = 'p';

    //c_str return const char*, but this usage is quite popular.
    const char* temp = y.c_str();

    y[0] = 'p';

    //Now we expect "pello" because the standart says the pointer points to the actual data
    //but we will get "hello"
    cout << "temp = " << temp << endl; 



    return 0;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
146 views
Welcome To Ask or Share your Answers For Others

1 Answer

You're right that COW is disallowed. But GCC hasn't updated its implementation yet, allegedly due to ABI constraints. A new implementation, designed eventually to supplant the std::string implementation, can be found as ext/vstring.h.

A bug in libstdc++'s std::string, albeit not this one, is not going to make it into GCC 4.9; Jonathan indicates on the bug that it has only been fixed for vstring so far. My guess would be, then, that the COW issue would be resolved around the same time.

Despite all this, casting away constness then mutating is pretty much always a bad idea: though you're correct that this should in practice be safe with a fully C++11-compliant string implementation, you're making assumptions and this very problem proves that you cannot always rely on those assumptions to hold. So, while your code example may be "popular", it's popular in poor code, and shouldn't be written even now. And, of course, writing that in C++03 is flat-out incompetence!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...