На днях я писал код, похожий на:
wchar_t buffer[1024];
std::wifstream input(L"input.txt");
while (input.good())
{
input::getline(buffer, 1024);
// ... do stuff...
}
input.close();
Я обнаружил, что после первого вызова getline
, buffer
содержал правильные байты данных (UTF-16 LE), но вместо того, чтобы buffer
воспринимался как массив wchar_t, он волшебным образом преобразовывался в массив байтов. Я reinterpret_cast<wchar_t *>(buffer)
и получил желаемый результат.
Затем следующий вызов getline
... на этот раз буфер снова воспринимался как массив байтов, но байты были искажены. Я ожидал увидеть 0x31 0x00 0x32 0x00 0x33 0x00
, но вместо этого увидел 0x00 0x31 0x00 0x32 0x00 0x33
Теперь я могу понять, как все может быть искажено, если символы имеют кодировку переменной длины... но ВСЕ символы в моем файле input.txt являются ASCII и, следовательно, могут быть закодированы с помощью 2 байтов каждый (с использованием UTF16-LE). Почему перекос?
Ответчик на SO сообщил мне, что я должен наполнить поток так:
std::wifstream fin("text.txt", std::ios::binary);
// apply facet
fin.imbue(std::locale(fin.getloc(),
new std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>));
Действительно, это полностью решило мою проблему. Я не понимаю, зачем нужно наполнение, если все символы, с которыми вы имеете дело, имеют кодировку фиксированной длины?
Во-вторых, второй параметр для наполнения похоже на утечку памяти?! Если я выделяю объект std::codecvt_utf16<wchar_t, 0x10ffff, std::little_endian>
в стеке и передаю его адрес в imbue, кажется, что все работает до тех пор, пока моя переменная стека не выйдет за пределы области видимости (прямо перед основной закрывающей скобкой). Приложение вылетает, жалуясь, что какая-то функция вызывает чисто виртуальную функцию. Я вижу такое же поведение, если я использую предоставленный код и вместо этого вызываю удаление в памяти до того, как main вернется.
Заранее спасибо за ваши комментарии и ответы.