Я делаю некоторые работы по техническому обслуживанию и натыкался на что-то как следующее:
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] было бы безопасно, если бы это был станд.:: вектор, но это безопасное использование станд.:: строка?
Распределение 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]
работу со строками нулевой длины (на самом деле, это было явно неопределённое поведение), и старая ревизия этого ответа объясняла это; это было исправлено в более поздних стандартных чертежах, поэтому ответ был соответствующим образом обновлен.
Код может работать, но больше по удаче, чем по суждению, он делает предположения о реализации, которые не гарантированы. Я полагаю, что определение действительности кода не имеет значения, в то время как это бессмысленное излишнее усложнение, которое легко сводится к простому:
std::string s( str ) ;
или, если присваивать существующему объекту std::string, просто:
s = str ;
и затем позволить самому std::string определить, как достичь результата. Если вы собираетесь прибегнуть к подобным глупостям, то с тем же успехом вы можете не использовать std::string и придерживаться его, так как вы вновь вводите все опасности, связанные со строками на C.
.Технически нет, так как std::string
не требуется для хранения его содержимого в последовательной памяти.
Однако почти во всех реализациях (каждая из которых мне известна) содержимое хранится непрерывно, и это "работает".
. Читатели должны отметить, что этот вопрос был задан в 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 );
?
Последовательности поддерживаются массивами символов, поэтому я не думаю, что можно уменьшить количество экземпляров символов [], не уменьшая количество последовательностей.
Пытались ли вы удалить некоторые последовательности, чтобы увидеть, не уменьшился ли также символ []?
-121--3572535- В документах утверждается, что существует 4 различных место хранения двигателя. Модуль FallbackStorage
выполняет запись в сеанс.
Это, как правило, не безопасно, независимо от того, хранится ли внутренняя последовательность строк в памяти непрерывно или нет. Кроме непрерывности, может быть много других деталей реализации, связанных с тем, как управляемая последовательность хранится объектом std:: string
.
Реальной практической проблемой с этим может быть следующее. Управляемая последовательность std:: string
не должна храниться как строка с нулевым окончанием. Однако на практике многие (большинство?) реализации выбирают избыточный размер внутреннего буфера на 1 и сохраняют последовательность как строку с нулевым окончанием в любом случае, потому что это упрощает реализацию метода c _ str ()
: просто верните указатель на внутренний буфер, и вы закончите.
Код, который вы процитировали в вашем вопросе, не пытается обнулить данные, копируется во внутренний буфер. Вполне возможно, он просто не знает, необходимо ли нулевое прекращение для этой реализации std:: Последовательности
. Вполне возможно, что он полагается на внутренний буфер, заполняемый нулями после вызова resize
, так что дополнительный символ, выделенный для ограничителя нуля реализацией, удобно предварительно устанавливается равным нулю. Все это - деталь реализации, означающая, что этот прием зависит от некоторых довольно хрупких предположений.
Другими словами, в некоторых реализациях, вероятно, придется использовать strcpy
, а не memcpy
, чтобы принудительно ввести данные в управляемую последовательность. В некоторых других реализациях необходимо использовать memcpy
, а не strcpy
.