В последнее время я делал некоторые необходимые оптимизации. Одна вещь, которую я делал, - это изменение некоторых ostringstreams -> sprintfs. Я sprintf'ing кучу std :: strings в массив стиля AC, аля
char foo[500];
sprintf(foo, "%s+%s", str1.c_str(), str2.c_str());
Оказывается, что реализация Microsoft std :: string :: c_str () выполняется за постоянное время (она просто возвращает внутренний указатель). Похоже, что libstdc ++ делает то же самое . Я понимаю, что std не дает никаких гарантий для c_str, но сложно представить другой способ сделать это. Если, например, они скопировали в память, им либо пришлось бы выделить память для буфера (предоставив вызывающей стороне его уничтожить - НЕ часть контракта STL) ИЛИ им пришлось бы скопировать во внутреннюю статическую память. буфер (вероятно, не потокобезопасный, и у вас нет никаких гарантий на его время жизни). Так что простой возврат указателя на внутренне поддерживаемую строку с нулевым символом в конце кажется единственным реальным решением.
источник
c_str
что это метод const (или, по крайней мере, имеет перегрузку const - я забыл, какой), это не меняет логическое значение, поэтому может быть причинойmutable
. Это сломало бы указатели от других вызововc_str
, за исключением того, что любые такие указатели должны ссылаться на одну и ту же логическую строку (так что нет никакой новой причины для перераспределения - там уже должен быть нулевой терминатор), иначе должен был уже быть вызов не -константный метод между ними.c_str
вызовы могут быть O (n) время для перераспределения и копирования. Но также возможно, что в стандарте есть дополнительные правила, о которых я не знаю, которые могли бы предотвратить это. Причина, по которой я это предлагаю - вызовы наc_str
самом деле не предназначены для того, чтобы быть обычным AFAIK, поэтому может не считаться важным обеспечить их быструю работу - избегая лишнего байта памяти для обычно ненужного нулевого терминатора вstring
случаях, которые никогда не используются,c_str
может имеют приоритет.Boost.Format
внутренне проходит через потоки, которые внутренне проходят,sprintf
заканчивая довольно большими накладными расходами. Документация говорит, что это примерно в 8 раз медленнее, чем обычноеsprintf
. Если вы хотите производительность и безопасность типов, попробуйтеBoost.Spirit.Karma
.Boost.Spirit.Karma
Это хороший совет для производительности, но имейте в виду, что у него совершенно другая методология, которая может быть сложной для адаптации существующегоprintf
кода стиля (и кодеров). Я в основном придерживался,Boost.Format
потому что наш ввод / вывод асинхронный; но важным фактором является то, что я могу убедить своих коллег использовать его последовательно (все еще допускает любой тип сostream<<
перегрузкой - что приятно обходит стороной.c_str()
дебаты). Показатели эффективности Karma .В стандарте c ++ 11 (я читаю версию N 3290) глава 21.4.7.1 говорит о методе c_str ():
const charT* c_str() const noexcept; const charT* data() const noexcept;
Итак, да: сложность с постоянным временем гарантируется стандартом.
Я только что проверил стандарт C ++ 03, и он не имеет таких требований, и это не говорит о сложности.
источник
В теории C ++ 03 этого не требует, и, следовательно, строка может быть массивом char, в котором присутствие нулевого терминатора добавляется только во время вызова c_str (). Это может потребовать перераспределения (это не нарушает постоянство, если внутренний закрытый указатель объявлен как
mutable
).C ++ 11 более строгий: он требует затрат времени, поэтому перемещение не может быть выполнено, и массив всегда должен быть достаточно широким, чтобы хранить ноль в конце. c_str () сама по себе может делать "
ptr[size()]='\0'
", чтобы гарантировать, что значение null действительно присутствует. Это не нарушает постоянство массива, так как диапазон[0..size())
не изменяется.источник