Обработка строк в C ++ - C++ string handling - Wikipedia

В C ++ язык программирования поддерживает обработка строк, в основном реализовано в стандартная библиотека. Стандарт языка определяет несколько строковых типов, некоторые из которых унаследованы от C, некоторые предназначены для использования функций языка, таких как классы и RAII. Наиболее часто используемые из них: std :: string.

Поскольку в начальных версиях C ++ был только «низкоуровневый» Обработка строки C функциональность и соглашения, несколько несовместимых проектов для классов обработки строк были разработаны на протяжении многих лет и все еще используются вместо std :: string, а программистам на C ++ может потребоваться обработка нескольких соглашений в одном приложении.

История

В std :: string type - это основной строковый тип данных в стандарте C ++ с 1998 года, но он не всегда был частью C ++. От C C ++ унаследовал соглашение об использовании строки с завершающим нулем которыми занимается указатель к их первому элементу и библиотеке функций, которые управляют такими строками. В современном стандартном C ++ строковый литерал, например "Привет" по-прежнему обозначает массив символов с завершающим нулем.[1]

Использование классов C ++ для реализации строкового типа дает несколько преимуществ автоматизированного управление памятью и сниженный риск доступа за пределы площадки,[2] и более интуитивно понятный синтаксис для сравнения и конкатенации строк. Поэтому было очень соблазнительно создать такой класс. За прошедшие годы разработчики приложений, библиотек и фреймворков C ++ создали свои собственные несовместимые строковые представления, такие как AT&T библиотека стандартных компонентов (первая такая реализация, 1983 г.)[3] или CString введите Microsoft MFC.[4] Пока std :: string стандартизированные строки, устаревшие приложения по-прежнему обычно содержат такие настраиваемые типы строк, а библиотеки могут ожидать строки в стиле C, что делает «практически невозможным» избежать использования нескольких типов строк в программах на C ++[1] и требуя от программистов выбора желаемого строкового представления перед запуском проекта.[4]

В ретроспективе истории C ++ 1991 г. его изобретатель Бьярне Страуструп назвал отсутствие стандартного строкового типа (и некоторых других стандартных типов) в C ++ 1.0 худшей ошибкой, которую он сделал при его разработке; «их отсутствие привело к тому, что все заново изобрели колесо и к ненужному разнообразию в самых фундаментальных классах».[3]

Проблемы реализации

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

нить а = "Привет!";нить б = а; // Копируем конструктор

фактически не копирует содержимое а к б; вместо этого обе строки разделяют свое содержимое и счетчик ссылок на содержание увеличивается. Фактическое копирование откладывается до тех пор, пока операция изменения, такая как добавление символа в любую строку, не приведет к различию содержимого строк. Копирование при записи может существенно изменить производительность кода, использующего строки (делая некоторые операции намного быстрее, а некоторые - медленнее). Хотя std :: string больше не использует его, многие (возможно, большинство) альтернативных строковых библиотек по-прежнему реализуют строки с функцией копирования при записи.

Некоторые строковые реализации хранят 16-битные или 32-битные кодовые точки вместо байтов это предназначалось для облегчения обработки Unicode текст.[5] Однако это означает, что преобразование в эти типы из std :: string или из массивов байтов - это медленная и часто с потерями операция, зависящая от «локали», и может вызывать исключения.[нужна цитата ] Какие-либо преимущества обработки 16-битных кодовых единиц исчезли, когда переменная ширина UTF-16 было введено кодирование (хотя есть еще преимущества, если вы должны взаимодействовать с 16-битным API, таким как Windows). Qt с QString это пример.[5]

Сторонние строковые реализации также значительно различались по синтаксису для извлечения или сравнения подстрок или для выполнения поиска в тексте.

Стандартные типы строк

В std :: string class - стандартное представление текстовой строки, поскольку C ++ 98. Класс предоставляет некоторые типичные строковые операции, такие как сравнение, объединение, поиск и замену, а также функцию для получения подстроки. An std :: string может быть построена из строки в стиле C, а строка в стиле C.[6]

Отдельные единицы, составляющие строку, относятся к типу char, как минимум (и почти всегда) по 8 бит. В современном обиходе это часто не «персонажи», а части кодировка многобайтовых символов Такие как UTF-8.

Стратегия копирования при записи была намеренно разрешена первоначальным стандартом C ++ для std :: string потому что это считалось полезной оптимизацией и использовалось почти во всех реализациях.[6] Однако были ошибки, в частности оператор [] вернул неконстантную ссылку, чтобы упростить перенос C на месте строковых манипуляций (такой код часто предполагал один байт на символ, и, следовательно, это могло быть не очень хорошей идеей!) Это позволило следующий код, который показывает, что это должен сделать копию, даже если она почти всегда используется только для проверки строки, а не для ее изменения:[7][8]

  стандартное::нить оригинал("ааааааа");  стандартное::нить string_copy = оригинал; // сделать копию  char* указатель = &string_copy[3]; // некоторые пытались заставить operator [] возвращать "хитрый" класс, но это усложняло  random_code_here(); // никакие оптимизации не могут это исправить  *указатель = 'b'; // если operator [] не копировал, это неожиданно изменило бы оригинал

Это вызвало некоторые реализации[который? ] отказаться от копирования при записи. Также было обнаружено, что накладные расходы в многопоточный приложения из-за блокировки, необходимой для проверки или изменения счетчика ссылок, были больше, чем накладные расходы на копирование небольших строк на современных процессорах[9] (особенно для строк меньше размера указателя). Оптимизация была окончательно запрещена в C ++ 11,[7] в результате даже пройдя std :: string в качестве аргумента функции, а именно.

пустота Распечатать(стандартное::нить s) { стандартное::cout << s; }

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

пустота Распечатать(const стандартное::нить& s) { стандартное::cout << s; }

В C ++ 17 добавил новый string_view учебный класс[10] это только указатель и длина для данных только для чтения, что делает передачу аргументов намного быстрее, чем любой из приведенных выше примеров:

пустота Распечатать(стандартное::string_view s) { стандартное::cout << s; }...  стандартное::нить Икс = ...;  Распечатать(Икс); // не копирует x.data ()  Распечатать("это буквальная строка"); // также не копирует символы!...


Пример использования

#включают <iostream>#включают <string>int главный(){    стандартное::нить фу("истребители");    стандартное::нить бар("табурет");    если (фу != бар)        стандартное::cout << «Струны разные». << стандартное::конец;    стандартное::cout << "Строка =" << бар << стандартное::конец;    возвращаться 0;}

Родственные классы

std :: string это typedef для конкретного экземпляра std :: basic_string класс шаблона.[11] Его определение можно найти в <string> заголовок:

typedef basic_string<char> нить;

Таким образом нить обеспечивает basic_string функциональность для строк, имеющих элементы типа char. Есть аналогичный класс std :: wstring, который состоит из wchar_t, и чаще всего используется для хранения UTF-16 текст на Windows и UTF-32 на большинстве Unix-подобный платформы. Однако стандарт C ++ не требует какой-либо интерпретации как Unicode кодовых точек или кодовых единиц для этих типов и даже не гарантирует, что wchar_t содержит больше бит, чем char.[12] Чтобы устранить некоторые несовместимости, возникающие из-за wchar_tсвойства, C ++ 11 добавлены два новых класса: std :: u16string и std :: u32string (состоит из новых типов char16_t и char32_t), которые представляют собой заданное количество бит на единицу кода на всех платформах.[13]C ++ 11 также добавил новые строковые литералы 16-битных и 32-битных «символов» и синтаксиса для помещения кодовых точек Unicode в строки с завершающим нулем (в стиле C).[14]

А basic_string гарантированно специализируется на любом типе с char_traits структура, чтобы сопровождать это. Начиная с C ++ 11, только char, wchar_t, char16_t и char32_t требуется реализация специализаций в стандартной библиотеке; любые другие типы определяются реализацией.[15] Каждая специализация также является Контейнер стандартной библиотеки, и, следовательно, Алгоритмы стандартной библиотеки может применяться к единицам кода в строках.

Критика

Дизайн std :: string был представлен в качестве примера монолитного дизайна Херб Саттер, который считает, что из 103 функций-членов класса в C ++ 98 71 могла быть развязанный без потери эффективности внедрения.[16]

Рекомендации

  1. ^ а б Сикорд, Роберт С. (2013). Безопасное кодирование на C и C ++. Эддисон-Уэсли. ISBN  9780132981972.
  2. ^ Уаллин, Стив (2003). Практическое программирование на C ++. О'Рейли.
  3. ^ а б Страуструп, Бьярне (1993). История C ++: 1979–1991 (PDF). Proc. ACM История языков программирования, конф.
  4. ^ а б Солтер, Николас А .; Клепер, Скотт Дж. (2005). Профессиональный C ++. Джон Вили и сыновья. п. 23. ISBN  9780764589492.
  5. ^ а б Бланшетт, Жасмин; Саммерфилд, Марк (2008). Программирование графического интерфейса на C ++ с помощью Qt4. Pearson Education. ISBN  9780132703000.
  6. ^ а б Мейерс, Скотт (2012), Эффективный STL, Addison-Wesley, pp. 64–65, ISBN  9780132979184
  7. ^ а б Мередит, Алисдэр; Бем, Ганс; Краул, Лоуренс; Димов, Петр (2008). «Модификации параллелизма в базовой строке». ISO / IEC JTC 1 / SC 22 / WG 21. Получено 19 ноября 2015.
  8. ^ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=21334
  9. ^ Саттер, Херб (1999). «Оптимизации, которых нет (в многопоточном мире)». Журнал пользователей C / C ++. 17 (6).
  10. ^ "std :: basic_string_view - cppreference.com". en.cppreference.com. Получено 23 июн 2016.
  11. ^ "Справочник C ++ для basic_string". Cppreference.com. Получено 11 января 2011.
  12. ^ Гиллам, Ричард (2003). Демистификация Unicode: практическое руководство программиста по стандарту кодирования. Эддисон-Уэсли Профессионал. п. 714. ISBN  9780201700527.
  13. ^ "C ++ 11 Paper N3336". Открытые стандарты. Язык программирования C ++, рабочая группа библиотеки. 13 января 2012 г.. Получено 2 ноября 2013.
  14. ^ Страуструп, Бьярн (2013). Язык программирования C ++. Эддисон Уэсли. п. 179. Архивировано с оригинал 25 ноября 2015 г.. Получено 24 ноября 2015.
  15. ^ "char_traits - Справочник по C ++". Получено 1 августа 2015.
  16. ^ Саттер, Херб. «Монолиты» без струн"". gotw.ca. Получено 23 ноября 2015.