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