Как устроены строки в C++?

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

Ответ

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

1. Строки в стиле C (C-strings)

Это массивы символов (char или wchar_t), завершающиеся нуль-терминатором ('').

const char* cstr = "Hello"; // "Hello" хранится в статической памяти
char cstr_array[] = {"World"}; // Массив на стеке: 'W','o','r','l','d',''
char stack_str[10]; // Буфер, который нужно заполнять аккуратно
strcpy(stack_str, "Hi"); // Опасность: strcpy не проверяет границы буфера.
// Безопаснее (C11/C++): strncpy(stack_str, "Hi", sizeof(stack_str));

Недостатки: Управление памятью вручную, риск переполнения буфера, сложность операций (требуют функций из <cstring>).

2. Класс std::stringstd::wstring)

Это специализация шаблона std::basic_string для типа char. Он инкапсулирует динамический массив символов.

#include <string>
#include <iostream>

std::string s1; // Пустая строка
std::string s2 = "Initial"; // Инициализация из C-строки
std::string s3(10, 'x'); // "xxxxxxxxxx"
std::string s4(s2, 0, 3); // "Ini" (подстрока)

// Основные операции
s2.append(" Value"); // "Initial Value"
s2 += "!"; // Конкатенация
size_t pos = s2.find("Val"); // pos = 8
std::string sub = s2.substr(pos, 5); // "Value"
s2.replace(pos, 5, "Data"); // "Initial Data!"

// Доступ к данным
char ch = s2[0]; // 'I' (без проверки границ)
char ch_safe = s2.at(0); // 'I' (с проверкой, throws std::out_of_range)
const char* c_ptr = s2.c_str(); // Для передачи в C-API
const char* data_ptr = s2.data(); // Доступ к внутреннему массиву (C++17)

Внутреннее устройство (SSO - Small String Optimization): Во многих реализациях std::string использует оптимизацию для коротких строк. Небольшие строки (до ~15-23 символов, зависит от реализации) хранятся внутри самого объекта на стеке, избегая динамического выделения памяти. Длинные строки хранят указатель на память в куче.

std::string short_str = "SSO!"; // Вероятно, хранится в буфере внутри объекта
std::string long_str = "This is a very long string that will require heap allocation";

Ключевые преимущества std::string:

  • Автоматическое управление памятью: Само расширяется при конкатенации.
  • Безопасность: Методы проверяют границы (например, at()).
  • Богатый интерфейс: Поиск, замена, вставка, сравнение.
  • Совместимость с STL: Работает с алгоритмами (std::sort, std::find) и итераторами.
  • Поддержка внутри строки: std::string s = "ABCD"; содержит 5 символов, в отличие от C-строки.