std::wstring vs std::string: что выбрать для Unicode?

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: две строки, одна головная боль

Каждый C++ разработчик рано или поздно сталкивается с дилеммой: std::string или std::wstring? Вроде бы оба — строки, оба из STL, но ведут себя совершенно по-разному. Особенно остро этот вопрос встаёт при работе с многоязычным текстом, эмодзи или иероглифами.

Если вы пишете на C++ и хотите, чтобы ваша программа корректно обрабатывала «Привет, мир!» на русском, японском или арабском — без понимания разницы между std::string и std::wstring не обойтись. В этой статье мы разберём оба подхода, сравним их по ключевым параметрам и решим, когда какой использовать.

Этот материал основан на реальном вопросе с Stack Overflow, собравшем тысячи просмотров. Мы адаптировали его для образовательных целей, добавив примеры и чёткую структуру.

std::string: классика и простота

std::string — это псевдоним для std::basic_string<char>. Каждый символ занимает 1 байт. Исторически сложилось, что char использовался для ASCII-символов, но сегодня он чаще всего хранит данные в кодировке UTF-8 (или просто байты).

Плюсы std::string

  • Экономия памяти — 1 байт на символ для ASCII/UTF-8.
  • Совместимость — работает с большинством библиотек, включая C-функции (strlen, strcpy).
  • Скорость — меньше накладных расходов на аллокацию.
  • Повсеместность — стандарт де-факто для передачи данных по сети и в JSON.

Минусы std::string

  • Путаница с кодировками — std::string не знает, в какой кодировке хранятся данные. Вы можете хранить в нём UTF-8, но .size() вернёт количество байт, а не символов.
  • Проблемы с Unicode — итерация по строке может разбить многобайтовый символ.
  • Нет встроенной поддержки широких символов — для работы с Unicode вне UTF-8 придётся подключать сторонние библиотеки.
// Пример: std::string с UTF-8
#include <iostream>
#include <string>

int main() {
    std::string s = "Привет, мир!";
    std::cout << "Длина в байтах: " << s.size() << std::endl; // 21 байт
    std::cout << "Первый символ (как char): " << s[0] << std::endl; // Мусор: первый байт UTF-8
    return 0;
}

В этом примере s[0] вернёт не 'П', а первый байт двухбайтового символа 'П' (0xD0). Это частая ошибка новичков.

std::wstring: мощь широких символов

std::wstring — это std::basic_string<wchar_t>. Размер wchar_t зависит от платформы: 2 байта на Windows (UTF-16) и 4 байта на Linux/macOS (UTF-32).

Плюсы std::wstring

  • Фиксированный размер символа (на конкретной платформе) — упрощает работу с Unicode.
  • Прямая поддержка локалей — в Windows все WinAPI-функции работают с wchar_t.
  • Меньше проблем с многобайтовыми символами — каждый символ — это один элемент строки.

Минусы std::wstring

  • Размер зависит от платформы — код может вести себя по-разному на Windows и Linux.
  • Больший расход памяти — 2 или 4 байта на символ, даже для ASCII.
  • Проблемы с совместимостью — не все библиотеки поддерживают wchar_t.
  • Суррогатные пары — в UTF-16 некоторые символы (например, эмодзи) занимают 2 wchar_t, что снова создаёт проблему «символ ≠ элемент».
// Пример: std::wstring на Windows
#include <iostream>
#include <string>

int main() {
    std::wstring ws = L"Привет, мир!";
    std::wcout << L"Длина: " << ws.size() << std::endl; // 12 символов (на Windows)
    std::wcout << L"Первый символ: " << ws[0] << std::endl; // 'П' (корректно)
    return 0;
}

Обратите внимание: на Windows ws.size() вернёт 12 (количество символов), а не 21, как в случае с std::string. Но на Linux wchar_t занимает 4 байта, и размер строки может отличаться.

Сравнение в таблице

Характеристика std::string std::wstring
Тип символа char (1 байт) wchar_t (2 или 4 байта)
Кодировка по умолчанию Не определена (часто UTF-8) UTF-16 (Windows) / UTF-32 (Linux)
Размер в памяти (ASCII) 1 байт/символ 2 или 4 байта/символ
Поддержка Unicode Требует внешней обработки Встроенная (но с нюансами)
Переносимость Высокая Средняя (зависит от платформы)
Использование в WinAPI Требует конвертации Напрямую

Когда что выбирать?

Выбирайте std::string, если:

  • Вы работаете с кроссплатформенным кодом.
  • Вам нужна минимальная память и

Блоги

Рекомендаций по книгам