Конструктор копирования std::string НЕ глубоко в GCC 4.1.2?

Интересно, я что-то неправильно понял: конструктор копирования из std::string не копирует свое содержимое?

string str1 = "Hello World";
string str2(str1);

if(str1.c_str() == str2.c_str()) // Same pointers!
  printf ("You will get into the IPC hell very soon!!");

Это напечатает «Очень скоро вы попадете в ад IPC!!» и меня это раздражает.

Это нормальное поведение std::string? Я где-то читал, что он обычно делает глубокую копию.

Однако это работает так, как ожидалось:

string str3(str1.c_str());

if(str1.c_str() == str3.c_str()) // Different pointers!
  printf ("You will get into the IPC hell very soon!!");
else
  printf ("You are safe! This time!");

Он копирует содержимое в новую строку.


person Philipp Michalski    schedule 17.05.2013    source источник
comment
Попробуйте изменить str2 в первом примере (например, str2[0] = 'B';) и затем сравнить значения c_str().   -  person Angew is no longer proud of SO    schedule 17.05.2013
comment
Что бы это ни стоило, GCC 4.7 имеет одинаковое поведение как в режимах C++ 03, так и в режимах C++ 11 (и предложение @Angew действительно дает разные значения c_str()).   -  person syam    schedule 17.05.2013
comment
По-видимому, он выделяет новый буфер после редактирования, которое вы предложили @Angew. Так что, похоже, это какая-то оптимизация... нам потребовалось несколько часов работы, чтобы найти эту проблему. *вздох*   -  person Philipp Michalski    schedule 17.05.2013


Ответы (2)


Вполне возможно, что ваша реализация string использует копирование при записи, что объясняет такое поведение. Хотя это менее вероятно для более новых реализаций (и несовместимых с реализациями C++11).

Стандарт не накладывает ограничений на значение указателя, возвращаемого c_str (кроме того, что он указывает на c-строку с завершающим нулем), поэтому ваш код по своей сути непереносим.

person pmr    schedule 17.05.2013
comment
Почему COW менее вероятен в новых реализациях. - person user93353; 17.05.2013
comment
@ user93353 COW невозможно реализовать, если вы хотите соответствовать С++ 11: stackoverflow.com/questions/12199710/ - person pmr; 17.05.2013
comment
@ user93353: COW может сильно снизить производительность в многопоточных средах. По этой причине он потерял большую популярность (и был запрещен в C++11). - person Grizzly; 17.05.2013
comment
@ user93353 Многие люди не согласны с многопоточностью. Есть также семантика перемещения, которая обрабатывает множество классических случаев, когда COW был полезен. - person pmr; 17.05.2013
comment
Ага, как ты сказал. Полезно знать СЕЙЧАС... Спасибо! Я приму ваш ответ позже, я просто подожду, если кто-то еще скажет что-то интересное по этому поводу. - person Philipp Michalski; 17.05.2013
comment
Как я сказал в другом комментарии, GCC 4.7 в режиме C++11 ведет себя так же. Глядя на исходники /usr/include/c++/4.7/bits/basic_string.h, это действительно COW (а как насчет соответствия C++11?...). - person syam; 17.05.2013
comment
@syam Это считается дефектом и может измениться: stackoverflow.com/questions/12520192/ и связанный поток. - person pmr; 17.05.2013

std::string реализация в вашем компиляторе должна иметь подсчет ссылок. Измените одну из строк, а затем снова проверьте указатели - они будут другими.

string str1 = "Hello World";
string str2(str1);

if(str1.c_str() == str2.c_str()) // Same pointers!
  printf ("You will get into the IPC hell very soon!!");

str2.replace(' ',',');

// Check again here.

Это 3 отличные статьи о строках с подсчетом ссылок.

http://www.gotw.ca/gotw/043.htm

http://www.gotw.ca/gotw/044.htm

http://www.gotw.ca/gotw/045.htm

person user93353    schedule 17.05.2013
comment
Я сделал, как я указал в своем комментарии к самому вопросу, и, как сказано выше: он делает копию при записи! - person Philipp Michalski; 17.05.2013