Урок №202. Длина и ёмкость std::string

  Юрий  | 

  |

  Обновл. 15 Сен 2021  | 

 68465

 ǀ   8 

При создании строки не помешало бы указать её длину и ёмкость (или хотя бы знать эти параметры).

Длина std::string

Длина строки — это количество символов, которые она содержит. Есть две идентичные функции для определения длины строки:

   size_type string::length() const

   size_type string::size() const

Обе эти функции возвращают текущее количество символов, которые содержит строка, исключая нуль-терминатор. Например:

Результат:

6

Хотя также можно использовать функцию length() для определения того, содержит ли строка какие-либо символы или нет, эффективнее использовать функцию empty():

   bool string::empty() const — эта функция возвращает true, если в строке нет символов, и false — в противном случае.

Например:

Результат:

false
true

Есть еще одна функция, связанная с длиной строки, которую вы, вероятно, никогда не будете использовать, но мы все равно её рассмотрим:

   size_type string::max_size() const — эта функция возвращает максимальное количество символов, которое может хранить строка. Это значение может варьироваться в зависимости от операционной системы и архитектуры операционной системы.

Например:

Результат:

2147483647

Ёмкость std::string


Ёмкость строки — это максимальный объем памяти, выделенный строке для хранения содержимого. Это значение измеряется в символах строки, исключая нуль-терминатор. Например, строка с ёмкостью 8 может содержать 8 символов.

   size_type string::capacity() const — эта функция возвращает количество символов, которое может хранить строка без дополнительного перераспределения/перевыделения памяти.

Например:

Результат:

Length: 10
Capacity: 15

Примечание: Запускать эту и следующие программы следует в полноценных IDE, а не в веб-компиляторах.

Обратите внимание, ёмкость строки больше её длины! Хотя длина нашей строки равна 10, памяти для неё выделено аж на 15 символов! Почему так?

Здесь важно понимать, что, если пользователь захочет поместить в строку больше символов, чем она может вместить, строка будет перераспределена и, соответственно, ёмкость будет больше. Например, если строка имеет длину и ёмкость равную 10, то добавление новых символов в строку приведет к её перераспределению. Делая ёмкость строки больше её длины, мы предоставляем пользователю некоторое буферное пространство для расширения строки (добавление новых символов).

Но в перераспределении есть также несколько нюансов:

   Во-первых, это сравнительно ресурсозатратно. Сначала должна быть выделена новая память. Затем каждый символ строки копируется в новую память. Если строка большая, то тратится много времени. Наконец, старая память должна быть удалена/освобождена. Если вы делаете много перераспределений, то этот процесс может значительно снизить производительность вашей программы.

   Во-вторых, всякий раз, когда строка перераспределяется, её содержимое получает новый адрес памяти. Это означает, что все текущие ссылки, указатели и итераторы строки становятся недействительными!

Обратите внимание, не всегда строки создаются с ёмкостью, превышающей её длину. Рассмотрим следующую программу:

Результат:

Length: 15
Capacity: 15

Примечание: Результаты могут отличаться в зависимости от компилятора.

Теперь давайте добавим еще один символ в конец строки и посмотрим на изменение её ёмкости:

Результат:

Length: 15
Capacity: 15
Length: 16
Capacity: 31

Есть еще одна функция (а точнее 2 варианта этой функции) для работы с ёмкостью строки:

   void string::reserve(size_type unSize) — при вызове этой функции мы устанавливаем ёмкость строки, равную, как минимум, unSize (она может быть и больше). Обратите внимание, для выполнения этой функции может потребоваться перераспределение.

   void string::reserve() — если вызывается эта функция или вышеприведенная функция с unSize меньше текущей ёмкости, то компилятор попытается срезать (уменьшить) ёмкость строки до размера её длины. Это необязательный запрос.

Например:

Результат:

Length: 10
Capacity: 15
Length: 10
Capacity: 303
Length: 10
Capacity: 303

Здесь мы можем наблюдать две интересные вещи. Во-первых, хотя мы запросили ёмкость равную 300, мы фактически получили 303. Ёмкость всегда будет не меньше, чем мы запрашиваем (но может быть и больше). Затем мы запрашиваем изменение ёмкости в соответствии со строкой. Этот запрос был проигнорирован, так как, очевидно, что ёмкость не изменилась.

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

Результат этой программы будет меняться при каждом её новом запуске:

tregsxxmselsqlfoahsvsxfmfwurcmmjclfcqqgzkzohztirriibtoibucswaudyirkvjbwxfysoqzcc

Вместо того, чтобы перераспределять sString несколько раз, мы устанавливаем её ёмкость один раз, а затем просто заполняем данными.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (114 оценок, среднее: 4,95 из 5)
Загрузка...

Комментариев: 8

  1. Павел:

     Во-вторых, всякий раз, когда строка перераспределяется, её содержимое получает новый адрес памяти. Это означает, что все текущие ссылкиуказатели и итераторы строки становятся недействительными!

    Не совсем понял что имеется ввиду. Попробовал проверить:

    Length: 6
    Capacity: 15
    ptr: 000000A93C1BF108
    Capacity: 31
    *ptr: string
    ptr: 000000A93C1BF108
    ptr1 000000A93C1BF108

    После увеличения емкости старый и новый указатель указывают на один адрес.

  2. Maks:

    Вместо std::string::reserve() для уменьшения ёмкости строки до размера её длины, лучше использовать std::string::shrink_to_fit (С++11)

  3. Влад:

    Подскажите, допустим мне надо просто перебрать все элементы строки в цикле:

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

    Или от этой оптимизации толку нет?

    1. Alexandr:

      Думаю не стоит, т.к. размер строки может измениться.

    2. Jaegar:

      Теоретически — вы правы.
      Практически — современные компиляторы невероятно мощные программы, и подобные вещи будут оптимизированы компилятором без проблем, так что не стоит волноваться об этом.

    3. Павел:

      Ваша программа выводит «Hello, Word!» str.length() раз

      просто запишет длину строки в переменную.

      Если нужно вывести строку посимвольно

      Если нужно записать строку посимвольно

      Но здесь уже в пустую строку у меня закладывает Capacity: 15 символов. Так что для одного-двух слов можно заранее не резервить емкость при посимвольном заполнении.

      Теперь вопросы:

      Емкость определяется во время компиляции? Если так, то и для ввода большой строки одним махом тоже не нужно резервировать емкость? И для ввода — потому что getline или std::cin принимают уже готовый ввод?

  4. Кашпировский:

    Если писать строку более 195 Идет ошибка Out of range — Ну я не знаю что делать ?

    1. Пётр:

      Вы делаете массив стрингов и после пытаетесь к массиву применить метод, надо применять к элементу массива тогда уж. Полный код приводите, а то непонятно вообще, что вы хотите.

Добавить комментарий для Павел Отменить ответ

Ваш E-mail не будет опубликован. Обязательные поля помечены *