Какие возможные реализации и представления строк существуют в C++?

«Какие возможные реализации и представления строк существуют в C++?» — вопрос из категории C++ Core, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В C++ эволюционировали несколько способов работы со строками, каждый со своей областью применения.

  1. C-строки (Null-terminated strings) Массивы символов типа char (или wchar_t для широких символов), где конец строки обозначается нулевым символом ''. Это наследие языка C.

    • Плюсы: Универсальность, работа с любым C API.
    • Минусы: Сложное ручное управление памятью, риск переполнения буфера, линейный поиск длины (O(n)).
      char cstr[] = "Hello"; // Массив из 6 char: 'H','e','l','l','o',''
      const char* ptr = "Literal"; // Указатель на строковый литерал в read-only памяти
  2. std::stringstd::wstring) Класс из Стандартной библиотеки (<string>), который инкапсулирует динамический массив символов. Это основной способ работы со строками в современном C++.

    • Плюсы: Автоматическое управление памятью (RAII), богатый интерфейс (поиск, конкатенация, модификация), знает свою длину (O(1)).
    • Минусы: Небольшие накладные расходы на хранение размера и ёмкости.
      #include <string>
      std::string s1 = "Hello";
      std::string s2 = s1 + " World!"; // Конкатенация
      size_t len = s2.length(); // Длина = 12
  3. std::string_view (C++17) Невладеющее, неизменяемое (read-only) представление подстроки. Содержит только указатель на данные и длину. Аналог span для строк.

    • Плюсы: Лёгковесный (размер ~2 указателя), не выделяет память, идеален для передачи строк в функции только для чтения, устраняет ненужные копии.
    • Минусы: Не владеет данными, поэтому исходная строка должна переживать string_view. Нельзя использовать для хранения.
      #include <string_view>
      void process(std::string_view sv) { // Принимает и std::string, и C-строку
      // Чтение sv[0], sv.substr(...)
      }
      std::string str = "...";
      process(str); // Нет копирования данных строки
      process("literal"); // Создаётся временный string_view
  4. std::basic_string с пользовательским аллокатором Шаблонный класс, лежащий в основе std::string (std::basic_string<char>). Позволяет кастомизировать тип символа (char, wchar_t, char16_t, char32_t) и стратегию выделения памяти.

    using wstring = std::basic_string<wchar_t>; // std::wstring
    // Пользовательский аллокатор для особых случаев (например, arena-аллокатор)
    template<typename T>
    class MyAllocator { /*...*/ };
    using CustomString = std::basic_string<char, std::char_traits<char>, MyAllocator<char>>;

Практическое правило: Для владения строковыми данными используйте std::string. Для передачи строк в функции (только для чтения) используйте std::string_view. Для взаимодействия с C-библиотеками иногда необходимы C-строки (метод c_str() у std::string).