Хорошо, даже если оставить за бортом индексацию (которая вообще-то крайне полезна, если мы работаем с текстом как с массивом символов), то что же делать с regex? Можете сто раз сказать «графемные кластеры», легче от этого не станет.
Код символа целое число, в C/C++ есть достаточно вместимый тип для любого кода Юникод из возможных — это int32_t, так что если нужно соответствие 1:1, то его легко можно получить.
Символ — это единичный элемент текста. В отрыве от кодировки. Сам по себе символ — это логическая сущность из мира человеческой логики, к машинным 0 и 1 не имеющая никакого отношения. Конечно же вас путает ключевое слово char, языков C/C++.
Распознать UTF-8 без BOM особого труда не составит, но вот проблема с короткими текстовыми файлами в этом случае останется, не так уж мало символов, начинающихся с 110 и 10. В этом смысле BOM гарантирует нам то, что текст закодирован в Unicode нужной кодировки. Для каждой кодировки Unicode свой BOM, описанный в стандарте. Костылями его считать можно только в случае если мы сидим исключительно под *nix в кодировке UTF-8 и считаем всё подряд UTF-8. Ребята из разработки Android NDK вообще не стесняются wstring считать строкой исключительно в UTF-8. Фактически кодировок больше чем одна и никакое распознавание не заменит простой заголовок текстового файла в несколько символов (с которым банально не умеет работать половина OpenSource софта, включая, до недавнего времени, Eclipse). Код должен быть кроссплатформенным и стабильным к косякам кривой перекодировки, которые вы будете неизбежно получать, пытаясь кодировку угадать.
Если взять QString с внутренним представлением int32_t на символ с ленивым преобразованием из входящей закодированной строки, с кэшем до первого не-const вызова, то вполне себе подойдёт. В QString много чего ещё стоило бы подкрутить.
Всё довольно просто, тема статьи касается в том числе отсутствия в стандартной библиотеке C++ типа представления вещественного числа с фиксированной точкой. В принципе если работаешь с БД с numeric/decimal типами, то преобразовывать их в типы float/double, а уж тем более держать строкой, не самое разумное решение. Поэтому для высокоуровневой работы и берут высокоуровневые языки.
Рад что статья вам понравилась. Действительно получилось немного похоже на QString, но хорошие решения всегда похожи. Есть ряд различий, я предлагаю внутреннее представление всё-таки на основе UTF-32 и позднюю переконвертацию (по необходимости) во внутреннее представление. Опять же подход из первой статьи позволит хранить в объекте базового класса любого его наследника, и таким образом выделить дерево текстовых типов, например для выделения текста лимитированной длины при работе с БД.
Для std::vector? Никакой не используется. Этот код одинаково алгоритмически эффективен для любой системы. Равно как и после оптимизации число выделений памяти в коде стало столь мало, что перестало иметь смысл искать «серебрянный» heap manager. Код просто стал работать быстро, независимо от менеджмента памяти в куче. Так и должен работать программист C++, его код либо эффективен, либо ему пора в Java.
Пример из статьи сильно упрощённый вариант реально произведённой оптимизации кода, который за каждым полем для хранения лазил в кучу, на продакшн версии. В результате оптимизации выделений памяти код обработки результатов запроса стал работать в среднем в 5 раз быстрее, так как львиную долю съедала именно работа с кучей из нескольких потоков одновременно.
P.S. Посмотри в конце концов на std::vector, его реализация не лазит за каждым элементов в кучу — он выполняет placement new. Ведь ты утверждаешь, что зря он это делает.
То есть для тебя 13 секунд простоя на каждые 100 млн объектов вообще не показатель? Я как бы напомню, что результат выборки SQL-запроса может быть весьма немалой таблицей разнотипных данных с кучей скаляров и NULL-значений. Это ещё однопоточный тест, здесь куча ещё более-менее в комфортной ситуации. Про Debug-режим, где каждый delete отзывается резкой болью и приводит к висякам при отладке, я даже не упоминаю. Если учесть, что рабочее высоконагруженное приложение в несколько потоков параллельно перелопачивает многие миллионы объектов на каждую операцию, то эти лишние секунды приведут к покупке новых серверов, вместо того, чтобы взять одного толкового программиста.
Никто не относится легко к неопределённому поведению. Фактически после уничтожения объекта считывать его нельзя. Вы правы. Посыпаю голову пеплом, за косяк к коде Академии C++. Фактически в operator = (object const&) должен быть принципиально другой код, копирующий, а не мувающий, с проверкой на this, как я и писал выше.
Зато приведённое решение позволяет сочетать динамическую типизацию и лёгкую замену имплементации (все данные спрятаны). Причём внешне программист работает с объектами по значению.
Какие милые детские мечты об идеальном memory manager, даже жаль разбивать веру человека в высшие силы, но мы представители точных наук. Вот тебе тест, можешь баловаться на любой машине: http://pastebin.com/GxvMkeEt
Не забудь выставить оптимизацию. Получается вот такое соотношение:
TEST STARTED WITH COUNT = 1234567
…
placement new: 0.011
heap new: 0.082
placement free: 0.005
heap free: 0.048
…
P.S. Вообще странно доказывать такие вещи программисту C++, обычно про идеально быстрое выделение памяти пишут программисты Java, у них это какая-то навязчивая идея.
Мы с Вами знаем, что приведённый код имеет академическое назначение. Ничего страшного не будет означает то, что любой косяк в приведённом коде обнаружит первый же юнит-тест при написании продукта на основе данного подхода.
Ну страшного ничего не будет, поскольку std::move выполняет перенос поэлементно. Другое дело, что по-хорошему нужен другой метод для оператора копирования copy_data_to, а move_data_to должен переехать в оператор переноса operator = (object&& temporary), ну и обычная проверка на &another != this явно не помешает.
Это что такой за современный memory manager, что сгоняет в кучу за памятью, а потом заполнит эту память объектом, который делает это быстрее чем просто заполнение памятью объектом без первого шага?
P.S. Посмотри в конце концов на std::vector, его реализация не лазит за каждым элементов в кучу — он выполняет placement new. Ведь ты утверждаешь, что зря он это делает.
http://pastebin.com/GxvMkeEt
Не забудь выставить оптимизацию. Получается вот такое соотношение:
TEST STARTED WITH COUNT = 1234567
…
placement new: 0.011
heap new: 0.082
placement free: 0.005
heap free: 0.048
…
P.S. Вообще странно доказывать такие вещи программисту C++, обычно про идеально быстрое выделение памяти пишут программисты Java, у них это какая-то навязчивая идея.