Делает “&s [0]” точка к непрерывным символам в станд.:: строка?

Я делаю некоторые работы по техническому обслуживанию и натыкался на что-то как следующее:

std::string s;
s.resize( strLength );  
// strLength is a size_t with the length of a C string in it. 

memcpy( &s[0], str, strLength );

Я знаю, что использование &s [0] было бы безопасно, если бы это был станд.:: вектор, но это безопасное использование станд.:: строка?

37
задан John Dibling 18 February 2014 в 19:03
поделиться

5 ответов

Распределение std::string не гарантировано, что оно совпадает со стандартом C++98/03, но C++11 заставляет его совпадать. На практике ни я, ни Херб Саттер не знают о реализации, не использующей сопрягаемое хранилище.

Заметьте, что &s[0] вещь всегда гарантированно работает по стандарту C++11, даже в случае строки длиной 0. Это не будет гарантировано, если вы сделаете str.begin() или &*str.begin(), но для &s[0] стандарт определяет оператор operator[] как:

Returnns: *(begin() + pos), если pos < size(), в противном случае ссылка на объект типа T со значением charT(); ссылочное значение не должно быть изменено

Продолжая, data() определяется как: data():

Возвращает: Указатель p такой, что p + i == &operator[](i) для каждого i в [0,size()].

(обратите внимание на квадратные скобки на обоих концах диапазона)


Примечание: предстандартизация C++0x не гарантировала &s[0] работу со строками нулевой длины (на самом деле, это было явно неопределённое поведение), и старая ревизия этого ответа объясняла это; это было исправлено в более поздних стандартных чертежах, поэтому ответ был соответствующим образом обновлен.

42
ответ дан 27 November 2019 в 04:46
поделиться

Код может работать, но больше по удаче, чем по суждению, он делает предположения о реализации, которые не гарантированы. Я полагаю, что определение действительности кода не имеет значения, в то время как это бессмысленное излишнее усложнение, которое легко сводится к простому:

std::string s( str ) ;

или, если присваивать существующему объекту std::string, просто:

s = str ;

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

.
0
ответ дан 27 November 2019 в 04:46
поделиться

Технически нет, так как std::string не требуется для хранения его содержимого в последовательной памяти.

Однако почти во всех реализациях (каждая из которых мне известна) содержимое хранится непрерывно, и это "работает".

.
7
ответ дан 27 November 2019 в 04:46
поделиться

Читатели должны отметить, что этот вопрос был задан в 2009 году, когда в настоящее время был опубликован стандарт C ++ 03. Этот ответ основан на той версии Стандарта, в которой std :: string s не гарантированно используют непрерывное хранилище. Поскольку этот вопрос не задавался в контексте конкретной платформы (например, gcc), я не делаю никаких предположений о платформе OP - в частности, о погоде или отсутствии в ней использовалось постоянное хранилище для строки .

Законный? Может быть, а может и нет. Безопасный? Возможно, а может и нет. Хороший код? Что ж, не будем туда идти ...

Почему бы просто не сделать:

std::string s = str;

... или:

std::string s(str);

... или:

std::string s;
std::copy( &str[0], &str[strLen], std::back_inserter(s));

... или:

std::string s;
s.assign( str, strLen );

?

3
ответ дан 27 November 2019 в 04:46
поделиться

Последовательности поддерживаются массивами символов, поэтому я не думаю, что можно уменьшить количество экземпляров символов [], не уменьшая количество последовательностей.

Пытались ли вы удалить некоторые последовательности, чтобы увидеть, не уменьшился ли также символ []?

-121--3572535-

В документах утверждается, что существует 4 различных место хранения двигателя. Модуль FallbackStorage выполняет запись в сеанс.

-121--4648652-

Это, как правило, не безопасно, независимо от того, хранится ли внутренняя последовательность строк в памяти непрерывно или нет. Кроме непрерывности, может быть много других деталей реализации, связанных с тем, как управляемая последовательность хранится объектом std:: string .

Реальной практической проблемой с этим может быть следующее. Управляемая последовательность std:: string не должна храниться как строка с нулевым окончанием. Однако на практике многие (большинство?) реализации выбирают избыточный размер внутреннего буфера на 1 и сохраняют последовательность как строку с нулевым окончанием в любом случае, потому что это упрощает реализацию метода c _ str () : просто верните указатель на внутренний буфер, и вы закончите.

Код, который вы процитировали в вашем вопросе, не пытается обнулить данные, копируется во внутренний буфер. Вполне возможно, он просто не знает, необходимо ли нулевое прекращение для этой реализации std:: Последовательности . Вполне возможно, что он полагается на внутренний буфер, заполняемый нулями после вызова resize , так что дополнительный символ, выделенный для ограничителя нуля реализацией, удобно предварительно устанавливается равным нулю. Все это - деталь реализации, означающая, что этот прием зависит от некоторых довольно хрупких предположений.

Другими словами, в некоторых реализациях, вероятно, придется использовать strcpy , а не memcpy , чтобы принудительно ввести данные в управляемую последовательность. В некоторых других реализациях необходимо использовать memcpy , а не strcpy .

0
ответ дан 27 November 2019 в 04:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: