Std string npos c что это

Строки в языке C++ (класс string)

В языке C++ для удобной работы со строками есть класс string, для использования которого необходимо подключить заголовочный файл string.

Строки можно объявлять и одновременно присваивать им значения:

string S1, S2 = «Hello»;

Строка S1 будет пустой, строка S2 будет состоять из 5 символов.

Строки в языке C++ могут

Конструкторы строк

Конструкторы можно вызывать явно, например, так:

Неявно конструктор вызывается при объявлении строки с указанием дополнительных параметров. Например, так:

Подробней о конструкторах для строк читайте здесь.

Ввод-вывод строк

Строка выводится точно так же, как и числовые значения:

cout >» для объекта cin:

Можно считывать строки до появления символа конца строки при помощи функции getline. Сам символ конца строки считывается из входного потока, но к строке не добавляется:

Арифметические операторы

Подробней о методе resize.

clear

Подробней о методе clear.

empty

Подробней о методе empty.

push_back

Подробней о методе push_back.

append

Добавляет в конец строки несколько символов, другую строку или фрагмент другой строки. Имеет много способов вызова.

Подробней о методе append.

erase

Подробней о методе erase.

insert

Подробней о методе insert.

substr

Подробней о методе substr.

replace

Заменяет фрагмент строки на несколько равных символов, другую строку или фрагмент другой строки. Способы вызова аналогичны способам вызова метода append, только первыми двумя параметрами являются два числа: pos и count. Из данной строки удаляется count символов, начиная с символа pos, и на их место вставляются новые символы.

Подробней о методе replace.

Подробней о методе find.

rfind

Ищет последнее вхождение подстроки («правый» поиск). Способы вызова аналогичны способам вызова метода find.

Подробней о методе rfind.

find_first_of

Ищет в данной строке первое появление любого из символов данной строки str. Возвращается номер этого символа или значение string::npos.

find_last_of

Ищет в данной строке последнее появление любого из символов данной строки str. Способы вызова и возвращаемое значение аналогичны методу find_first_of.

Подробней о методе find_last_of.

find_first_not_of

Ищет в данной строке первое появление символа, отличного от символов строки str. Способы вызова и возвращаемое значение аналогичны методу find_first_of.

find_last_not_of

Ищет в данной строке последнее появление символа, отличного от символов строки str. Способы вызова и возвращаемое значение аналогичны методу find_first_of.

c_str

Возвращает указать на область памяти, в которой хранятся символы строки, возвращает значение типа char*. Возвращаемое значение можно рассматривать как C-строку и использовать в функциях, которые должны получать на вход C-строку.

Источник

Работа со строками на этапе компиляции в современном C++

Std string npos c что это. . Std string npos c что это фото. Std string npos c что это-. картинка Std string npos c что это. картинка

Если вы программируете на C++, то наверняка задавались вопросом почему нельзя сравнить два строковых литерала или выполнить их конкатенацию:

Впрочем, как говорится, «нельзя, но если очень хочется, то можно». Ломать стереотипы будем под катом, причем прямо на этапе компиляции.

Зачем все это нужно

В одном из проектов, над которым я работал, было принято использовать std::string в качестве строковых констант. В проекте было несколько модулей, в которых были определены глобальные строковые константы:

Кроме того, такой подход имеет еще ряд недостатков. Во-первых, брошенное при создании глобального объекта исключение не отлавливается. Во-вторых, инициализация происходит при выполнении программы, что тратит драгоценное процессорное время.

Именно тогда у меня возникла идея о работе со строками на этапе компиляции, которая в итоге и привела к написанию этой статьи.

В этой статье рассмотрим строки, операции над которыми можно проводить на этапе компиляции. Назовем такие строки статическими.

Все реализованные операции были включены в библиотеку для работы со статическими строками. Исходные коды библиотеки доступны на github, ссылка в конце статьи.

Для использования библиотеки требуется как минимум C++14.

Определение статической строки

Определим статическую строку как массив символов, для удобства будем считать, что строка всегда оканчивается нулевым символом:

Здесь можно пойти по другому пути, и определить строку как кортеж символов. Мне этот вариант показался более трудоемким и менее удобным. Поэтому здесь он рассмотрен не будет.

Создание статической строки

Посмотрите на определение строки hello выше, оно просто ужасно. Во-первых, нам нужно заранее вычислять длину массива. Во-вторых, нужно не забыть записать нулевой символ в конец. В-третьих, все эти запятые, скобки и кавычки. Определенно, с этим нужно что-то делать. Хотелось бы написать как-нибудь так:

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

Уже лучше, но индексы все же приходится писать руками. Здесь также отметим, что если указывать не все индексы, то можно получить подстроку строкового литерала, а если записать их в обратном порядке, то и его инверсию:

Это соображение очень пригодится нам в дальнейшем.

Теперь нам нужно как-то сгенерировать последовательность индексов строки. Для этого применим трюк с наследованием. Определим пустую структуру (нужно же что-то наследовать) с набором искомых индексов в качестве шаблонных параметров:

Определим структуру-генератор, которая будет генерировать индексы по одному, храня счетчик в первом параметре:

Позаботимся и о конечной точке рекурсии, когда все индексы сгенерированы (счетчик равен нулю), мы отбрасываем счетчик и генератор превращается в нужную нам последовательность:

В итоге, функция создания статической строки будет выглядеть так:

Напишем аналогичную функцию для статической строки, она пригодится нам далее:

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

Эта функция позволяет сделать ровно то, что мы хотели в начале главы.

В случае отсутствия аргументов будем возвращать пустую статическую строку, которая состоит только из нулевого символа:

Также нам понадобится создавать строку из кортежа символов:

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

Вывод статической строки в поток

Здесь все просто. Так как наша строка оканчивается нулевым символом, достаточно вывести в поток данные массива:

Преобразование статической строки в std::string

Здесь тоже ничего сложного. Инициализируем строку данными массива:

Сравнение статических строк

Будем сравнивать строки посимвольно, пока не выявим различия, либо не достигнем конца хотя бы одной из строк. Поскольку constexpr for еще не изобрели, воспользуемся рекурсией и тернарным оператором:

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

Такая версия компаратора позволит нам сравнивать не только строки целиком, но и отдельные подстроки.

Конкатенация статических строк

Для конкатенации используем тот же вариативный шаблон, что и в главе про создание статической строки. Инициализируем массив сначала символами первой строки (без учета нулевого символа), затем второй, и наконец добавляем нулевой символ в конец:

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

Операции поиска в статической строке

Рассмотрим операции поиска символа и подстроки в статической строке.

Поиск символа в статической строке

Поиск символа не представляет особенной сложности, рекурсивно проверяем символы по всем индексам и возвращаем первый индекс в случае совпадения. Также дадим возможность задавать начальную позицию поиска и порядковый номер совпадения:

Константа static_string_npos указывает на то, что поиск не увенчался успехом. Определим ее следующим образом:

Аналогично реализуем поиск в обратном направлении:

Определение вхождения символа в статическую строку

Для определения вхождения символа достаточно попробовать поискать его:

Подсчет количества вхождений символа в статическую строку

Подсчет количества вхождений реализуется тривиально:

Поиск подстроки в статической строке

Так как предполагается, что статические строки будут относительно небольшими, не будем здесь реализовывать алгоритм Кнута-Морриса-Пратта, реализуем простейший квадратичный алгоритм:

Аналогично реализуем поиск в обратном направлении:

Определение вхождения подстроки в статическую строку

Для определения вхождения подстроки достаточно попробовать поискать ее:

Определение, начинается/кончается ли статическая строка с/на заданной подстроки

Применив ранее описанный компаратор мы можем определить, начинается ли статическая строка с заданной подстроки:

Аналогично для окончания статической строки:

Работа с подстроками статической строки

Здесь рассмотрим операции, связанные с подстроками статической строки.

Получение подстроки, префикса и суффикса статической строки

Как мы отметили ранее, для получения подстроки нужно сгенерировать последовательность индексов, с заданным начальным и конечным индексами:

Реализуем получение подстроки с проверкой начала и конца подстроки с помощью static_assert :

Префикс — это подстрока, начало которой совпадает с началом исходной статической строки:

Аналогично для суффикса, только совпадает конец:

Разделение статической строки на две части по заданному индексу

Чтобы разделить статическую строку по заданному индексу, достаточно вернуть префикс и суффикс:

Реверсирование статической строки

Для реверсирования статической строки напишем генератор индексов, который генерирует индексы в обратном порядке:

Теперь реализуем функцию, которая реверсирует статическую строку:

Вычисление хэша статической строки

Вычислять хэш будем по следующей формуле:

H(s) = (s0 + 1) ⋅ 33 0 + (s1 + 1) ⋅ 33 1 +… + (sn — 1 + 1) ⋅ 33 n — 1 + 5381 ⋅ 33 n mod 2 64

Преобразование числа в статическую строку и обратно

Преобразование числа в статическую строку

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

Для получения всех цифр числа будем использовать генератор, аналогичный генератору последовательности индексов. Определим последовательность символов:

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

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

Следует также учесть случай, когда первоначальное число равно нулю, в этом случае нужно вернуть нулевой символ, иначе нуль будет преобразован в пустую последовательность символов, а потом и в пустую строку:

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

Будем обрабатывать число также, как показано выше, но с учетом знака:

Отбрасываем число после обработки, если оно отрицательно, добавим символ знака минуса:

Отдельно позаботимся о преобразовании нуля:

Наконец, реализуем функции преобразования:

Преобразование статической строки в число

Для преобразования статической строки в число нужно преобразовать символы в цифры, а затем сложить их, предварительно домножив на соответствующую степень десятки. Выполняем все действия рекурсивно, для пустой строки возвращаем нуль:

Для преобразования знаковых чисел, нужно учесть, что отрицательные числа начинаются с символа знака минуса:

Вопросы удобства использования библиотеки

К этому моменту библиотеку уже возможно полноценно использовать, но некоторые моменты вызывают неудобство. В этой главе рассмотрим как можно сделать использование библиотеки более удобным.

Объект статической строки

Упакуем строку и реализованные методы в объект. Это позволит использовать более короткие имена методов, а также реализовать операторы сравнения:

Операторы сравнения

Использование компаратора в виде функции неудобно и нечитаемо. Определим глобальные операторы сравнения:

Макросы работы с числами

Для удобства преобразования числа в статическую строку и обратно определим соотвествующие макросы:

Примеры использования библиотеки

Ниже приведены примеры реального использования реализованной библиотеки.

Конкатенация статических строк и строковых литералов:

Конкатенация статических строк, строковых литералов и чисел:

Итерация по символам в обоих направлениях:

Ссылки

Библиотеку, реализующую все вышеперечисленное, можно взять в моем github

Спасибо за внимание, замечания и дополнения приветствуются.

Update

Реализовал пользовательский литерал _ss для создания статических строк из строковых литералов:

Функцию make_static_string() запрятал во внутренний немспейс, все стало выглядеть приятнее:

Добавил шаблонный параметр Char вместо char:

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

Теперь все работает и для «широких» литералов:

Поправил метод size(), теперь size() и length() возвращают длину строки без учета нулевого символа, для получения размера массива нужно использовать sizeof():

Обновленная версия лежит на github
Спасибо всем за полезные комментарии.

Update 2

В ходе обсуждения с AndreySu появился еще один способ реализации статических строк, где символы передаются как шаблонные параметры:

Детальное рассмотрение этого варианта выходит за рамки статьи, буду рад, если кто-то из читателей займется доведением его до ума.

Источник

BestProg

Содержание

Поиск на других ресурсах:

1. Какое назначение класса string в программах на C++?
2. Какие модули (библиотеки) нужно подключить, чтобы использовать возможности класса string в MS Visual Studio C++?

Объявление переменной типа string осуществляется точно так же как и обычной переменной. Возможный вариант объявления с одновременной инициализацией.

Класс string есть удобен тем, что позволяет удобно манипулировать строками, используя стандартные (перегруженные) операторы.

С объектами класса string можно использовать нижеследующие операторы

Пример, который демонстрирует использование вышеприведенных операторов

6. Содержит ли класс string конструкторы?

Как и любой класс, класс string имеет ряд конструкторов. Основные из них следующие:

7. Примеры инициализации с помощью конструкторов

Ниже приведены примеры инициализации переменных типа string

Чтобы присвоить одну строку другой, можно применить один из двух методов:

Функция assign() имеет несколько перегруженных реализаций.

Первый вариант – это вызов функции без параметров

В этом случае происходит простое присваивание одной строки другой.

Второй вариант позволяет копировать заданное количество символов из строки:

Третий вариант функции assign() копирует в вызывающий объект первые num символов строки s :

Пример.

Однако, функция append() хорошо подходит, если нужно добавлять часть строки.

Функция имеет следующие варианты реализации:

Первый вариант функции позволяет вставить полностью всю строку s в заданную позицию start вызывающей строки (вызывающего объекта):

В вышеприведенных функциях:

Функция replace() выполняет замену символов в вызывающей строке. Функция имеет следующие варианты реализации:

Для удаления символов из вызывающей строки используется функция erase() :

Пример.

В классе string поиск строки в подстроке можно делать двумя способами, которые отличаются направлением поиска:

Прототип функции find() имеет вид:

Прототип функции rfind() имеет вид:

Пример 1. Фрагмент кода, который демонстрирует результат работы функции find()

Прототип функции compare() :

Пример. Демонстрация работы функции compare() :

Пример 2.

Для определения количества символов в строке используется функция length() без параметров.

Источник

Несколько подробностей об std::string

Недавно заинтересовался реализацией std::string в libstdc++. Не в связи с принятием нового стандарта, а чтобы разобраться. Благо требования к строковму типу почти не изменились.

Основным средством для анализа кода несомненно является метод пристального вглядывания, но чтобы сузить область вглядывывания и сделать процедуру более захватывающей можно реализовать для строки идиому «трассер» подсмотренную в «C++ Templates: The Complete Guide». Трассировка позволяет выявлять подозрительные интересные операции над строками.

выведет содержимое строки. Т.е. std::string — является, по сути, указателем на char.
Вобщем, эти и другие шокирующие поднобности под катом.

Структура

std::string декларируется как:
, в свою очередь, является псевдонимом для:

Определение basic_string выполнено в файлах c++/bits/basic_string.h c++/bits/basic_string.tcc.

Если убрать все методы класса, то останется

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

Подсчет ссылок

(Upd: _GLIBCXX_FULLY_DYNAMIC_STRING никакого отношения к refcounting’у не имеют. Это простая оптимизация для того, чтобы не выделять память для пустых строк. Отключать её нужно в тех случаях когда у вас несколько экземпляров libstdc++ в процессе (так бывает на Windows) )

В целом эти ссылки просто переносят выделение памяти с вызова констркутора к моменту первой записи в строку и иногда дают о себе знать при работе в мультипоточном режиме. Helgrind и drd выдают нетривиальные подсказки по этому поводу.

Трассер

Структура X имеет одно регулярное поле класса char v; — его значение. Два статических — массив счетчиков и массив имен для этих счетчиков. Подсчитываются вызовы конструкторов, деструкторов, присваиваний, сравнений(==, X(b);1102000a = [](X y)->X(b);0212000>0003000


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

operationctorcopyassgndtorlsseqlcast
<0000000
X a[10];10000000
std::copy(ch,ch+10,a);00100000
X b[10] = <'o'>;10000000
std::copy(a,a+10,b);00100000
>00020000

Теперь перейдем к строкам. Назовем нашу трасситуемую строку так
Конструирование пустых строк, как и ожидалось, не производит операций над символами.

operationctorcopyassgndtorlsseqlcast
<0000000
const xs s1;0000000
xs s2(s1);0000000
xs s3 = s1;0000000
>0000000

Следующая таблица говорит сама за себя. Смутило, что при указании длины(s2) количество операций значительно меньше чем в случае s1. Более того строки конструируемые на основе s1 и s2 повели себя разным образом. Для s6 ленивое конструирование сработало, для s5 — нет. Заполняющий конструктор так вообще удивил — откуда-то взялись дополнительные копирования и деструкторы. (Upd: они взялись из передачи класса по значению)

operationctorcopyassgndtorlsseqlcast
<0000000
xs s1((X*)«1234567890»);11011110110
xs s2((X*)«1234567890»,7);0080000
xs s3(10,’a’);13114000
xs s4(s1.begin(), s1.begin()+7);0080000
xs s5(s2);0000000
s5[0]=’a’;0090000
xs s6(s1);00110000
s6[0]=’a’;0010000
xs s7(s1,1,5);0060000
xs s8=[]()->xs();6066060

Теперь несколько базовых операций. Неожиданно, результат для resize получился значительно хуже чем для reserve:

operationctorcopyassgndtorlsseqlcast
int a = s1.size();0000000
s1.resize(100);131024000
s2.reserve(100);0080000
s1.erase();0010000

Что из этого можно вынести? Ну во первых использовать reserve, а не resize, избегать присвоений и заполняющих конструкторов, воможно, что-то еще. Код работает и дает сходный результат для g++ 4.7.2, intel 13.0.1, clang 3.2, что было проверено здесь
После выхода из области видимости строки деструкторы для символов не вызываются. Возможно там и другие операции пропускаются (например используется memcmp вместо в цикле). Но и строка это не полноценный контейнер. Для строк метод трассеров позволяет получить приблизительную оценку количества операций. Для чистых контейнеров эта оценка должна быть строже.

Вот, почти все.
Во время исследования никто не пострадал. Источниками были
этот референс, файлы:
/usr/include/c++/4.7.2/strings
/usr/include/c++/4.7.2/bits/stringfwd.h
/usr/include/c++/4.7.2./bits/basic_string.h
/usr/include/c++/4.7.2./bits/basic_string.tcc
и gdb.

В качестве постскриптума и иллюстрации тожества метапрограммирования добавлю, что наш трассер можно использовать для оценки затрат на разбор строки в boost::spirit. На гитхабе выложен исходник трассера вместе с примером calc5.cpp из boost::spirit.

Upd1:
Спасибо хабражителю Khim за разъяснение ситуации с _GLIBCXX_FULLY_DYNAMIC_STRING, cо строками c++11 и их реализацией в libstdc++.

Upd2: Согласно стандарту basic_string может оперировать только с POD типами. Оказалось, что X не является POD типом. (он «standard layout class», но не «trivially copyable class» т.к. имеет явные конструкторы, деструктор и операторы присвоения)
Поэтому поведение класса basic_string является неопределенным, а весь это пост — ложь и провокация. 🙂
Что и подтвеждается невозможностью скомпилировать примеры с использованием стандартных библиотек отличных от gnu libstdc++. (clang 3.2 c libc++ 1.0 и msvc из vs2012)

Источник

Добавить комментарий

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