При создании строки не помешало бы указать её длину и ёмкость (или хотя бы знать эти параметры).
Длина std::string
Длина строки — это количество символов, которые она содержит. Есть две идентичные функции для определения длины строки:
size_type string::length() const
size_type string::size() const
Обе эти функции возвращают текущее количество символов, которые содержит строка, исключая нуль-терминатор. Например:
1 2 3 4 5 6 7 8 9 |
#include <iostream> int main() { std::string sSomething("012345"); std::cout << sSomething.length() << std::endl; return 0; } |
Результат:
6
Хотя также можно использовать функцию length() для определения того, содержит ли строка какие-либо символы или нет, эффективнее использовать функцию empty():
bool string::empty() const — эта функция возвращает true
, если в строке нет символов, и false
— в противном случае.
Например:
1 2 3 4 5 6 7 8 9 10 11 |
#include <iostream> int main() { std::string sString1("Not Empty"); std::cout << (sString1.empty() ? "true" : "false") << std::endl; std::string sString2; // пустая строка std::cout << (sString2.empty() ? "true" : "false") << std::endl; return 0; } |
Результат:
false
true
Есть еще одна функция, связанная с длиной строки, которую вы, вероятно, никогда не будете использовать, но мы все равно её рассмотрим:
size_type string::max_size() const — эта функция возвращает максимальное количество символов, которое может хранить строка. Это значение может варьироваться в зависимости от операционной системы и архитектуры операционной системы.
Например:
1 2 3 4 5 6 7 |
#include <iostream> int main() { std::string sString("MyString"); std::cout << sString.max_size() << std::endl; } |
Результат:
Ёмкость std::string
Ёмкость строки — это максимальный объем памяти, выделенный строке для хранения содержимого. Это значение измеряется в символах строки, исключая нуль-терминатор. Например, строка с ёмкостью 8 может содержать 8 символов.
size_type string::capacity() const — эта функция возвращает количество символов, которое может хранить строка без дополнительного перераспределения/перевыделения памяти.
Например:
1 2 3 4 5 6 7 8 9 10 |
#include <iostream> int main() { std::string sString("0123456789"); std::cout << "Length: " << sString.length() << std::endl; std::cout << "Capacity: " << sString.capacity() << std::endl; return 0; } |
Результат:
Length: 10
Capacity: 15
Примечание: Запускать эту и следующие программы следует в полноценных IDE, а не в веб-компиляторах.
Обратите внимание, ёмкость строки больше её длины! Хотя длина нашей строки равна 10, памяти для неё выделено аж на 15 символов! Почему так?
Здесь важно понимать, что, если пользователь захочет поместить в строку больше символов, чем она может вместить, строка будет перераспределена и, соответственно, ёмкость будет больше. Например, если строка имеет длину и ёмкость равную 10, то добавление новых символов в строку приведет к её перераспределению. Делая ёмкость строки больше её длины, мы предоставляем пользователю некоторое буферное пространство для расширения строки (добавление новых символов).
Но в перераспределении есть также несколько нюансов:
Во-первых, это сравнительно ресурсозатратно. Сначала должна быть выделена новая память. Затем каждый символ строки копируется в новую память. Если строка большая, то тратится много времени. Наконец, старая память должна быть удалена/освобождена. Если вы делаете много перераспределений, то этот процесс может значительно снизить производительность вашей программы.
Во-вторых, всякий раз, когда строка перераспределяется, её содержимое получает новый адрес памяти. Это означает, что все текущие ссылки, указатели и итераторы строки становятся недействительными!
Обратите внимание, не всегда строки создаются с ёмкостью, превышающей её длину. Рассмотрим следующую программу:
1 2 3 4 5 6 7 8 9 10 |
#include <iostream> int main() { std::string sString("0123456789abcde"); std::cout << "Length: " << sString.length() << std::endl; std::cout << "Capacity: " << sString.capacity() << std::endl; return 0; } |
Результат:
Length: 15
Capacity: 15
Примечание: Результаты могут отличаться в зависимости от компилятора.
Теперь давайте добавим еще один символ в конец строки и посмотрим на изменение её ёмкости:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <iostream> int main() { std::string sString("0123456789abcde"); std::cout << "Length: " << sString.length() << std::endl; std::cout << "Capacity: " << sString.capacity() << std::endl; // Добавляем новый символ sString += "f"; std::cout << "Length: " << sString.length() << std::endl; std::cout << "Capacity: " << sString.capacity() << std::endl; return 0; } |
Результат:
Length: 15
Capacity: 15
Length: 16
Capacity: 31
Есть еще одна функция (а точнее 2 варианта этой функции) для работы с ёмкостью строки:
void string::reserve(size_type unSize) — при вызове этой функции мы устанавливаем ёмкость строки, равную, как минимум, unSize
(она может быть и больше). Обратите внимание, для выполнения этой функции может потребоваться перераспределение.
void string::reserve() — если вызывается эта функция или вышеприведенная функция с unSize
меньше текущей ёмкости, то компилятор попытается срезать (уменьшить) ёмкость строки до размера её длины. Это необязательный запрос.
Например:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <iostream> int main() { std::string sString("0123456789"); std::cout << "Length: " << sString.length() << std::endl; std::cout << "Capacity: " << sString.capacity() << std::endl; sString.reserve(300); std::cout << "Length: " << sString.length() << std::endl; std::cout << "Capacity: " << sString.capacity() << std::endl; sString.reserve(); std::cout << "Length: " << sString.length() << std::endl; std::cout << "Capacity: " << sString.capacity() << std::endl; return 0; } |
Результат:
Length: 10
Capacity: 15
Length: 10
Capacity: 303
Length: 10
Capacity: 303
Здесь мы можем наблюдать две интересные вещи. Во-первых, хотя мы запросили ёмкость равную 300, мы фактически получили 303. Ёмкость всегда будет не меньше, чем мы запрашиваем (но может быть и больше). Затем мы запрашиваем изменение ёмкости в соответствии со строкой. Этот запрос был проигнорирован, так как, очевидно, что ёмкость не изменилась.
Если вы заранее знаете, что вам нужна строка побольше, так как вы будете выполнять с ней множество операций, которые потенциально могут увеличить её длину или ёмкость, то вы можете избежать перераспределений, сразу установив строке её окончательную емкость:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <iostream> #include <string> #include <cstdlib> // для rand() и srand() #include <ctime> // для time() int main() { srand(time(0)); // генерация случайного числа std::string sString; // длина 0 sString.reserve(80); // резервируем 80 символов // Заполняем строку случайными строчными символами for (int nCount = 0; nCount < 80; ++nCount) sString += 'a' + rand() % 26; std::cout << sString; } |
Результат этой программы будет меняться при каждом её новом запуске:
tregsxxmselsqlfoahsvsxfmfwurcmmjclfcqqgzkzohztirriibtoibucswaudyirkvjbwxfysoqzcc
Вместо того, чтобы перераспределять sString
несколько раз, мы устанавливаем её ёмкость один раз, а затем просто заполняем данными.
Вместо std::string::reserve() для уменьшения ёмкости строки до размера её длины, лучше использовать std::string::shrink_to_fit (С++11)
Подскажите, допустим мне надо просто перебрать все элементы строки в цикле:
Есть ли смысл перед циклом объявить переменную в которую записать длину строки, чтобы затем на каждой итерации цикла длина строки не рассчитывалась заного:
Или от этой оптимизации толку нет?
Думаю не стоит, т.к. размер строки может измениться.
Теоретически — вы правы.
Практически — современные компиляторы невероятно мощные программы, и подобные вещи будут оптимизированы компилятором без проблем, так что не стоит волноваться об этом.
Если писать строку более 195 Идет ошибка Out of range — Ну я не знаю что делать ?
Вы делаете массив стрингов и после пытаетесь к массиву применить метод, надо применять к элементу массива тогда уж. Полный код приводите, а то непонятно вообще, что вы хотите.