В стандартной библиотеке C++ std::string
имеет общедоступную функцию-член capacity()
, которая возвращает размер внутреннего выделенного хранилища, значение, большее или равное количеству символов в строке (согласно здесь). Для чего можно использовать это значение? Это как-то связано с пользовательскими распределителями?
Использование для значения емкости строки
Ответы (7)
Скорее всего, вы будете использовать функцию-член reserve()
, которая устанавливает емкость, по крайней мере, на указанное значение.
Сама функция-член capacity()
может использоваться, чтобы избежать выделения памяти. Например, вы можете перерабатывать использованные строки через пул и помещать каждую в корзину разного размера в зависимости от ее емкости. Затем клиент пула может запросить строку, которая уже имеет некоторую минимальную емкость.
capacity
при присвоении, он может перераспределяться для сжатия.
- person MSalters; 21.05.2010
capacity()
, которое кажется правильным (т. е. пытаетесь избежать дорогостоящего перераспределения).
- person dreamlax; 27.05.2010
Функция string::capacity()
возвращает общее количество символов, которое может содержать std::string
, прежде чем ей потребуется перераспределить память, что является довольно дорогостоящей операцией.
std::vector
работает таким же образом, поэтому я предлагаю вам посмотреть std::vector
здесь для подробного объяснения разницы между выделенной и инициализированной памятью.
Обновить
Хм, я вижу, что неправильно понял вопрос, на самом деле я думаю, что сам никогда не использовал capacity() ни для std::string, ни для std::vector, кажется, это редко имеет какую-либо причину, поскольку вам все равно нужно вызывать резерв.
Он дает вам количество символов, которое может содержать строка, без необходимости повторного выделения. Я предполагаю, что это может быть важно в ситуации, когда выделение было дорогим, и вы хотели этого избежать, но я должен сказать, что это одна строковая функция-член, которую я никогда не использовал в реальном коде.
Его можно использовать для некоторой настройки производительности, если вы собираетесь добавить в строку много символов. Перед началом манипуляций со строкой вы можете проверить емкость и, если она слишком мала, зарезервировать желаемую длину за один шаг (вместо того, чтобы позволить ему последовательно перераспределять большие куски памяти несколько раз, что приведет к снижению производительности).
reserve()
может выделить больше памяти, даже если в этом нет необходимости, и хотя capacity()
, скорее всего, встроена, reserve()
с меньшей вероятностью, поскольку она будет больше (поэтому вызов capacity()
может быть дешевле в случае, когда вам не понадобится reserve()
). Однако на самом деле, скорее всего, дело в полноте. Кто-то может захотеть узнать емкость, и у него может быть действительно веская причина, по которой разработчики библиотеки не могли ее предвидеть. Хотя обычно это не нужно, иметь его не помешает, и это может быть полезно.
- person Jonathan M Davis; 21.05.2010
Строки имеют емкость и размер. Емкость указывает, сколько символов может содержать строка, прежде чем ей потребуется выделить больше памяти. Размер указывает, сколько символов он в настоящее время содержит. reserve()
можно использовать для установки минимальной емкости строки (будет выделена память для минимум этого количества символов, но может быть выделено и больше).
Это в первую очередь важно, если вы увеличиваете размер строки. Когда вы объединяете строку с помощью +=
или append()
, символы из данной строки будут добавлены в конец текущей. Если увеличение строки до этого размера не превышает емкость, то она просто будет использовать имеющуюся емкость. Однако, если новый размер превысит текущую емкость, тогда строка должна будет перераспределить внутреннюю память и скопировать свои внутренние компоненты в новую память. Если вы собираетесь делать это часто, это может стать дорогостоящим (хотя это делается в амортизированное постоянное время), поэтому в таком случае вы можете использовать reserve()
для предварительного выделения достаточного количества памяти, чтобы уменьшить частоту перераспределения. .
векторные функции в основном одинаковы с теми же функциями.
Лично, хотя я время от времени имел дело с capacity()
и reserve()
с вектором, я никогда не видел особой необходимости делать это со строкой - вероятно, потому, что я обычно не делаю достаточно конкатенаций строк в своем коде, чтобы это стоило Это. В большинстве случаев конкретная строка может получить несколько конкатенаций, но этого недостаточно, чтобы беспокоиться о ее емкости. Как правило, вы беспокоитесь о емкости, когда пытаетесь оптимизировать свой код.
reserve
, но почему важно знать текущую емкость строки?
- person dreamlax; 21.05.2010
reserve()
и избежать множественных перераспределений. Но вы не обязательно знали бы, нужно ли вам это, если бы вы сначала не проверили емкость. Однако в большинстве случаев вы, вероятно, будете иметь дело с только что созданной строкой и просто вызовете reserve()
, не беспокоясь о capacity()
.
- person Jonathan M Davis; 21.05.2010
Вряд ли есть какое-либо релевантное использование. Это похоже на std::vector::capacity. Однако одним из наиболее распространенных применений строк является присваивание. При назначении std::string его .capacity может измениться. Это означает, что реализация имеет право игнорировать старую емкость и точно выделять достаточно памяти.
Это действительно не очень полезно и, вероятно, существует только для симметрии с vector
(при условии, что оба будут работать внутри одинаково).
Емкость вектора гарантированно повлияет на поведение изменения размера. Изменение размера вектора до значения, меньшего или равного емкости, не вызовет перераспределения и, следовательно, не сделает недействительными итераторы или указатели, ссылающиеся на элементы в векторе. Это означает, что вы можете предварительно выделить часть памяти, вызвав резерв для вектора, а затем (с осторожностью) добавить к нему элементы, изменив размер или отодвинув назад (и т. д.), зная, что базовый буфер не будет перемещаться.
Однако для string
такой гарантии нет. Кажется, что емкость предназначена только для информационных целей, хотя даже это с натяжкой, поскольку в любом случае не похоже, что из нее можно извлечь какую-либо полезную информацию. (Хуже того, непрерывность строковых символов также не гарантируется, поэтому единственный способ получить строку в виде линейного буфера — это c_str()
, что может привести к перераспределению.)
Предположительно, string
изначально предполагалось реализовать как некий частный случай vector
, но со временем они разошлись...