Гарантируется ли стандартом размещение элементов строки в непрерывном блоке памяти, как это сделано для вектора? И имеет ли строка нуль терминатор равный *(string.end()). Спасибо
Здравствуйте, Аноним, Вы писали:
А>Гарантируется ли стандартом размещение элементов строки в непрерывном блоке памяти, как это сделано для вектора? И имеет ли строка нуль терминатор равный *(string.end()). Спасибо
Гарантируется если вызовешь c_str(), а в целом в большинстве реализаций STL не прерывный блок.
*(string.end()) выражение НЕ КОРРЕКТНО ВСЕГДА!!!! НИКОГДА НЕ ПИШИ ТАКОЕ
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Аноним, Вы писали:
А>>Гарантируется ли стандартом размещение элементов строки в непрерывном блоке памяти, как это сделано для вектора? И имеет ли строка нуль терминатор равный *(string.end()). Спасибо А>Гарантируется если вызовешь c_str(), а в целом в большинстве реализаций STL не прерывный блок.
Неверно. c_str() возвращает строку вида const char* заканчивающуюся 0, но никто не гарантирует, что эта строка будет ссылаться на корректное внутреннее представление. Иными словами c_str() может вернуть указатель на временный кеш, в котором будет собираться строка, а внутри она может храниться как угодно и если вы преобразуете значение, возвращаемое c_str() в char* и попытаетесь его изменить — это ни к чему не приведёт в лучшем случае, в худшем всё может упасть...
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Здравствуйте, Mr. None, Вы писали:
MN>Здравствуйте, Аноним, Вы писали:
А>>Здравствуйте, Аноним, Вы писали:
А>>>Гарантируется ли стандартом размещение элементов строки в непрерывном блоке памяти, как это сделано для вектора? И имеет ли строка нуль терминатор равный *(string.end()). Спасибо А>>Гарантируется если вызовешь c_str(), а в целом в большинстве реализаций STL не прерывный блок.
MN>Неверно. c_str() возвращает строку вида const char* заканчивающуюся 0, но никто не гарантирует, что эта строка будет ссылаться на корректное внутреннее представление. Иными словами c_str() может вернуть указатель на временный кеш, в котором будет собираться строка, а внутри она может храниться как угодно и если вы преобразуете значение, возвращаемое c_str() в char* и попытаетесь его изменить — это ни к чему не приведёт в лучшем случае, в худшем всё может упасть...
Меня всегда интересовал такой вопрос: если предположить что c_str() возвращает указатель на временный кеш, кто его должен освобождать и как. По логике освободить кэш должна вызывающая сторона, но как ?
Мне здесь видится некое лукавство стандарта, с одной стороны не гарантируется непрерывное размещение элементов строки, а с другой стороны c_str() должна возвращать указатель на непрерывный блок оканчивающийся 0.
Уважаемый ALL подскажите реализации STL использующие для строк различные несмежные блоки памяти, хотелось бы посмотреть устройство и логику работы string.
Здравствуйте, Demay, Вы писали:
А>>>>Гарантируется ли стандартом размещение элементов строки в непрерывном блоке памяти, как это сделано для вектора? И имеет ли строка нуль терминатор равный *(string.end()). Спасибо А>>>Гарантируется если вызовешь c_str(), а в целом в большинстве реализаций STL не прерывный блок.
MN>>Неверно. c_str() возвращает строку вида const char* заканчивающуюся 0, но никто не гарантирует, что эта строка будет ссылаться на корректное внутреннее представление. Иными словами c_str() может вернуть указатель на временный кеш, в котором будет собираться строка, а внутри она может храниться как угодно и если вы преобразуете значение, возвращаемое c_str() в char* и попытаетесь его изменить — это ни к чему не приведёт в лучшем случае, в худшем всё может упасть...
D>Меня всегда интересовал такой вопрос: если предположить что c_str() возвращает указатель на временный кеш, кто его должен освобождать и как. По логике освободить кэш должна вызывающая сторона, но как ?
Кто мешает держать этот кэш внутри себя, обновлять при вызове c_str() и удалять при разрушении... Заметьте, никто не гарантирует даже следующего:
const char *str = someStlStr.c_str();
SomeFunc(str); // не факт, что здесь была передана верная строка...
И уж тем более никто не гарантирует, что будет работать это:
const char *str = someStlStr.c_str();
someStlStr += "qwert";
SomeFunc(str); // вот я не берусь сказать, что вы передали...
D>Уважаемый ALL подскажите реализации STL использующие для строк различные несмежные блоки памяти, хотелось бы посмотреть устройство и логику работы string.
Да пожалуйста: реализации stl идущие с MS VC 6.0 — 7.1 включительно... Они оптимизируют хранение строк малых размеров и внутри себя содержат 2 буфера — один выделенный статически размером в 15 символов, другой выделяется динамически, если строка вылезает за пределы 15 символов...
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
[...]
MN>Кто мешает держать этот кэш внутри себя, обновлять при вызове c_str() и удалять при разрушении... Заметьте, никто не гарантирует даже следующего: MN>
MN>const char *str = someStlStr.c_str();
MN>SomeFunc(str); // не факт, что здесь была передана верная строка...
MN>
Для подтверждения выше приведенного примера нельзя ли дать ссылку на стандарт ?
А также правильно ли понял фразу: "не факт, что здесь была передана верная строка..."
Из этой фразы я понял, что можной найти такие условия, при которых result будет отличен от нуля, прошу указать мне такие условия:
char plain_str[] = "12345";
std::string someStlStr(plain_str);
const char *str = someStlStr.c_str();
SomeFunc(str); // не факт, что здесь была передана верная строка...int result = strcmp(str, plain_str);
MN>И уж тем более никто не гарантирует, что будет работать это: MN>
MN>const char *str = someStlStr.c_str();
MN>someStlStr += "qwert";
MN>SomeFunc(str); // вот я не берусь сказать, что вы передали...
MN>
D>>Уважаемый ALL подскажите реализации STL использующие для строк различные несмежные блоки памяти, хотелось бы посмотреть устройство и логику работы string.
MN>Да пожалуйста: реализации stl идущие с MS VC 6.0 — 7.1 включительно... Они оптимизируют хранение строк малых размеров и внутри себя содержат 2 буфера — один выделенный статически размером в 15 символов, другой выделяется динамически, если строка вылезает за пределы 15 символов...
В stl идущие с MS VC 6.0 — 7.1 имеется буфер статический, а если его недостаточно, то динамический, то в конкретный момент времени используется только один, а не оба сразу,
вы не поняли вопроса: Покажите мне реализацию stl которая использует для хранения несколько несмежных буферов, а затем сливает это все в один, а затем следуя вашей точке зрения освобождает его, надо полагать делать это она должна в деструкторе string.
[]
>> Освободить кэш должна вызывающая сторона, но как ? > > Кто мешает держать этот кэш внутри себя, обновлять при вызове c_str() и удалять при разрушении... Заметьте, никто не гарантирует даже следующего: >
> const char *str = someStlStr.c_str();
> SomeFunc(str); // не факт, что здесь была передана верная строка...
>
Факт. Стандарт гарантирует, что строка, полученная c_str(), остается валидной до первого вызова неконстантной ф-ции-члена строки.
Здравствуйте, MaximE, Вы писали:
ME>Mr. None wrote:
>> Кто мешает держать этот кэш внутри себя, обновлять при вызове c_str() и удалять при разрушении... Заметьте, никто не гарантирует даже следующего: >>
>> const char *str = someStlStr.c_str();
>> SomeFunc(str); // не факт, что здесь была передана верная строка...
>>
ME>Факт. Стандарт гарантирует, что строка, полученная c_str(), остается валидной до первого вызова неконстантной ф-ции-члена строки.
Сорри — погорячился
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Здравствуйте, Demay, Вы писали:
D>Здравствуйте, Mr. None, Вы писали:
D>Для подтверждения выше приведенного примера нельзя ли дать ссылку на стандарт ?
Сорри ошибся... в первом случае всё будет нормально, до тех пор пока не вызовете неконстантную функцию член...
MN>>Да пожалуйста: реализации stl идущие с MS VC 6.0 — 7.1 включительно... Они оптимизируют хранение строк малых размеров и внутри себя содержат 2 буфера — один выделенный статически размером в 15 символов, другой выделяется динамически, если строка вылезает за пределы 15 символов...
D>В stl идущие с MS VC 6.0 — 7.1 имеется буфер статический, а если его недостаточно, то динамический, то в конкретный момент времени используется только один, а не оба сразу, D>вы не поняли вопроса: Покажите мне реализацию stl которая использует для хранения несколько несмежных буферов, а затем сливает это все в один, а затем следуя вашей точке зрения освобождает его, надо полагать делать это она должна в деструкторе string.
Ну хотите я сам напишу? Я такой не видел, но это не означает, что такой не может быть. Такое поведение не противоречит стандарту, а следовательно возможно. Например, похожим образом может себя вести строка оптимизирующая операции конкатенации... Или строка поддерживающая многопоточный доступ — в этом случае возвращаемый из c_str буфер вообще может быть для каждого потока свой... топорно и не оптимально? — возможно... но вполне законно!
Вместо того, чтобы гадать вы скажите что вам действительно нужно. Ответ на вопрос "Гарантируется ли стандартом размещение элементов строки в непрерывном блоке памяти" дан — нет не гарантировано. А значение возвращаемое из c_str() вообще может быть копией и не ссылаться на внутреннее представление строки, так что, например, модифицировать его нельзя ни в коем случае.
Компьютер сделает всё, что вы ему скажете, но это может сильно отличаться от того, что вы имели в виду.
Здравствуйте, <Аноним>, Вы писали:
А>Гарантируется ли стандартом размещение элементов строки в непрерывном блоке памяти, как это сделано для вектора? И имеет ли строка нуль терминатор равный *(string.end()). Спасибо
Как уже было сказано предыдущими ораторами, способ представления строки зависит от реализации, не обязательно это должна быть последовательность. Но вот метод:
const charT * data() const;
Returns: If size() is nonzero, the member returns a pointer to the initial element of an array whose first size() elements equal the corresponding elements of the string controlled by *this. If size() is zero, the member returns a non-null pointer that is copyable and can have zero added to it.
Requires: The program shall not alter any of the values stored in the character array. Nor shall the program treat the returned value as a valid pointer value after any subsequent call to a non-const member function of basic_string that designates the same object as this.
вполне можно использовать для получения образа всей строки в виде непрерывной последовательности символов.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
eao197 wrote:
> Здравствуйте, <Аноним>, Вы писали: > > А>Гарантируется ли стандартом размещение элементов строки в непрерывном блоке памяти, как это сделано для вектора? И имеет ли строка нуль терминатор равный *(string.end()). Спасибо > > Как уже было сказано предыдущими ораторами, способ представления строки зависит от реализации, не обязательно это должна быть последовательность. Но вот метод: >
> const charT * data() const;
>
> Returns: If size() is nonzero, the member returns a pointer to the initial element of an array whose first size() elements equal the corresponding elements of the string controlled by *this. If size() is zero, the member returns a non-null pointer that is copyable and can have zero added to it.
>
> Requires: The program shall not alter any of the values stored in the character array. Nor shall the program treat the returned value as a valid pointer value after any subsequent call to a non-const member function of basic_string that designates the same object as this.
> вполне можно использовать для получения образа всей строки в виде непрерывной последовательности символов.
Разница между data() и c_str() в том, что последний возвращает строку гарантированно заканчивающуюся нулем, в то время как для data() таких гарантий нет. Хотя реализации, которые мне известны (Dinkum, GNU, STLPort) всегда хранят строку, завершенную нулем, и для них data() и c_str() различий в реализации не имеют.
Здравствуйте, MaximE, Вы писали:
ME>Разница между data() и c_str() в том, что последний возвращает строку гарантированно заканчивающуюся нулем, в то время как для data() таких гарантий нет. Хотя реализации, которые мне известны (Dinkum, GNU, STLPort) всегда хранят строку, завершенную нулем, и для них data() и c_str() различий в реализации не имеют.
Как раз с завершающим нулем могут происходить неприятные сюрпризы. Если basic_string используется для сохранения двоичных данных (я, например, так часто делаю), то работа с ней как с C-строкой смысла не имеет: если в самой стороке есть 0-символ в середине, то конструкция:
strcpy( dest, src.c_str() );
не приведет к желаемому результату, т.к. будет скопирована только часть строки до первого 0-символа в середине. И в таких случаях я предпочитаю использовать data() вместо c_str() чтобы не расчитывать на наличие или отсутствие 0-символов.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
eao197 wrote:
> Здравствуйте, MaximE, Вы писали: > > ME>Разница между data() и c_str() в том, что последний возвращает строку гарантированно заканчивающуюся нулем, в то время как для data() таких гарантий нет. Хотя реализации, которые мне известны (Dinkum, GNU, STLPort) всегда хранят строку, завершенную нулем, и для них data() и c_str() различий в реализации не имеют. > > Как раз с завершающим нулем могут происходить неприятные сюрпризы. Если basic_string используется для сохранения двоичных данных (я, например, так часто делаю), то работа с ней как с C-строкой смысла не имеет.
А имеет ли смысл использовать string для двоичных данных? Я в таких случаях беру vector<char> — гарантированный memory layout + когда читаешь сразу ясно, что это не текст.
Здравствуйте, MaximE, Вы писали:
ME>eao197 wrote:
>> Здравствуйте, MaximE, Вы писали: >> >> ME>Разница между data() и c_str() в том, что последний возвращает строку гарантированно заканчивающуюся нулем, в то время как для data() таких гарантий нет. Хотя реализации, которые мне известны (Dinkum, GNU, STLPort) всегда хранят строку, завершенную нулем, и для них data() и c_str() различий в реализации не имеют. >> >> Как раз с завершающим нулем могут происходить неприятные сюрпризы. Если basic_string используется для сохранения двоичных данных (я, например, так часто делаю), то работа с ней как с C-строкой смысла не имеет.
ME>А имеет ли смысл использовать string для двоичных данных? Я в таких случаях беру vector<char> — гарантированный memory layout + когда читаешь сразу ясно, что это не текст.
Думаю, что иногда string удобнее -- поддерживаются операции контатенации, например.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
eao197 wrote:
>>> Как раз с завершающим нулем могут происходить неприятные сюрпризы. Если basic_string используется для сохранения двоичных данных (я, например, так часто делаю), то работа с ней как с C-строкой смысла не имеет. > > ME>А имеет ли смысл использовать string для двоичных данных? Я в таких случаях беру vector<char> — гарантированный memory layout + когда читаешь сразу ясно, что это не текст. > > Думаю, что иногда string удобнее -- поддерживаются операции контатенации, например.
Здравствуйте, MaximE, Вы писали:
ME>eao197 wrote:
>>>> Как раз с завершающим нулем могут происходить неприятные сюрпризы. Если basic_string используется для сохранения двоичных данных (я, например, так часто делаю), то работа с ней как с C-строкой смысла не имеет. >> >> ME>А имеет ли смысл использовать string для двоичных данных? Я в таких случаях беру vector<char> — гарантированный memory layout + когда читаешь сразу ясно, что это не текст. >> >> Думаю, что иногда string удобнее -- поддерживаются операции контатенации, например.
ME>
Здравствуйте, cMex, Вы писали: M>Здравствуйте, <Аноним>, Вы писали: А>>*(string.end()) выражение НЕ КОРРЕКТНО ВСЕГДА!!!! НИКОГДА НЕ ПИШИ ТАКОЕ M>В силу чего, если не секрет?
В силу того, что end итератор "указывающий" на элемент ЗА последним элементом строки(не путать с нулевым символом завершающим Си-строки!)
Re[5]: std::string as std::vector?
От:
Аноним
Дата:
04.05.05 10:01
Оценка:
Здравствуйте, Mr. None, Вы писали:
MN>Ну хотите я сам напишу? Я такой не видел, но это не означает, что такой не может быть. Такое поведение не противоречит стандарту, а следовательно возможно. Например, похожим образом может себя вести строка оптимизирующая операции конкатенации... Или строка поддерживающая многопоточный доступ — в этом случае возвращаемый из c_str буфер вообще может быть для каждого потока свой... топорно и не оптимально? — возможно... но вполне законно! MN>Вместо того, чтобы гадать вы скажите что вам действительно нужно. Ответ на вопрос "Гарантируется ли стандартом размещение элементов строки в непрерывном блоке памяти" дан — нет не гарантировано. А значение возвращаемое из c_str() вообще может быть копией и не ссылаться на внутреннее представление строки, так что, например, модифицировать его нельзя ни в коем случае.
Здравствуйте, LuciferMoscow, Вы писали:
LM>Здравствуйте, cMex, Вы писали: M>>Здравствуйте, <Аноним>, Вы писали: А>>>*(string.end()) выражение НЕ КОРРЕКТНО ВСЕГДА!!!! НИКОГДА НЕ ПИШИ ТАКОЕ M>>В силу чего, если не секрет? LM>В силу того, что end итератор "указывающий" на элемент ЗА последним элементом строки(не путать с нулевым символом завершающим Си-строки!)
ИМХО, вся стандартная библиотека в приложении к итератором контейнеров в качестве .end()-итератора и рассматривает именно элемент, расположенный за последним. Зачем это в частности достойно рассмотрено в книге Э. Кениг и Б. Му "Эффективное программирование" на С++. Поводов им не верить у меня нету.