Урок №210. Довжина і ємність std::string

  Юрій  | 

  Оновл. 8 Жов 2021  | 

 125

При створенні рядка не завадило б вказати його довжину і ємність (або хоча б знати ці параметри).

Довжина 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. Ємність завжди буде не менше, ніж ми просимо (але може бути і більше). Потім ми відсилаємо запит на зміну ємності відповідно рядку. Цей запит був проігнорований, тому що очевидно, що ємність не змінилася.

Якщо ви заздалегідь знаєте, що вам потрібен більший рядок, тому що ви виконуватимете з ним безліч операцій, які потенційно можуть збільшити його довжину або ємність, то ви можете уникнути перерозподілів, відразу встановивши рядку його остаточну ємність:

Результат цієї програми змінюватиметься при кожному її новому запуску:

tregsxxmselsqlfoahsvsxfmfwurcmmjclfcqqgzkzohztirriibto

Замість того, щоб перерозподіляти sString кілька разів, ми встановлюємо його ємність один раз, а потім просто заповнюємо даними.

Оцінити статтю:

1 Зірка2 Зірки3 Зірки4 Зірки5 Зірок (Немає Оцінок)
Loading...

Залишити відповідь

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