Является ли string:: c_str() разрешено выделять что-либо в куче?

Если мне нужно получить N60-завершенный массив char из std::string в ситуации, когда мне нужно быть уверенным, что ничего не будет выделено, можно ли использовать c_str для этого? Например, если я внутри деструктора, и я хочу скопировать некоторые данные из string в предварительно выделенный буфер фиксированного размера, могу ли я использовать c_str и быть уверенным, что он ничего не будет бросать?

Ответ 1

В стандарте указано, что вызов c_str() может привести к недействительности ссылок, указателей и интерпретаторов, относящихся к элементам string, что подразумевает, что разрешающая способность разрешена (21.3/5 "Шаблон класса basic_string" ).

Вы можете просто вызвать string::copy(), чтобы получить свою копию (вам нужно будет добавить нулевой ограничитель самостоятельно, если вам это нужно).

Ответ 2

Нет, стандарт не дает такой гарантии. Единственной гарантией в стандарте С++ является то, что возвращаемое значение указывает на массив char с тем же содержимым, что и std::string, плюс nul-terminator.

Таким образом, было бы стандартно-совместимо для реализации сохранять свое внутреннее представление каким-то образом, отличным от C-строки, и выделять C-строку "на лету", когда вы вызываете c_str, хотя я довольно уверен что широко используемая реализация STL на самом деле не делает этого.

Теперь, что касается С++ 0x, я слышал (хотя сейчас я затрудняюсь найти документацию для этого), что одним из изменений будет требование о том, чтобы std::string работало непрерывное хранилище (аналогичное требование уже существует для std::vector). Таким образом, в этом случае вы можете получить доступ к диапазону от &str[0] до &str[0]+str.length()-1, как если бы это была C-строка без nul-terminator.

Ответ 3

В стандарте не говорится об этом:

21.3.6 [lib.strings.ops]

const charT * c_str() const; 1 Возвращает: указатель на начальную элемент массива длины size() + 1, чьи элементы первого размера() равны соответствующие элементы строка, контролируемая * этим и чьи последний элемент является нулевым символом указанный charT().

2 Требуется: программа не должна изменить любое из значений, хранящихся в массив. Также программа не будет рассматривать возвращаемое значение как действительный указатель после любого последующего вызова неконстантная функция-член класса basic_string, который обозначает тот же объект как это.

Можно. Тем не менее, Iv'e никогда не видел никакой реализации, которая делает.

Если это вас беспокоит, вы можете захотеть использовать vector<char> вместо string и сделать что-то вроде:

vector<char> chars;
// ...
char* my_str = &chars[0];

Трюк здесь - это знать, когда и как справляться с необходимостью '\0' -терминированных строк.

Ответ 4

Стандарт, но явно указывает, что строка может выделять память при вызове c_str. В частности, он говорит (§21.3/5):

Ссылки, указатели и итераторы, относящиеся к элементам последовательности basic_string, могут быть аннулированы следующими видами использования этого объекта basic_string:
[...]
- Вызов функций() и c_str() функций-членов.

Он дает разрешение для указателей, ссылок и итераторов быть недействительными специально, чтобы позволить реализации переназначать память, используемую для хранения строки при вызове c_str.