Pull to refresh
48
0
Владимир Керимов @Qualab

User

Send message
Хорошо, даже если оставить за бортом индексацию (которая вообще-то крайне полезна, если мы работаем с текстом как с массивом символов), то что же делать с regex? Можете сто раз сказать «графемные кластеры», легче от этого не станет.
Код символа целое число, в C/C++ есть достаточно вместимый тип для любого кода Юникод из возможных — это int32_t, так что если нужно соответствие 1:1, то его легко можно получить.
Угу, очень удобно бегать по символам, при обходе regexp'ом. А уж индексация какая удобная! Константная сложность резко становится линейной.
Символ — это единичный элемент текста. В отрыве от кодировки. Сам по себе символ — это логическая сущность из мира человеческой логики, к машинным 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, как я и писал выше.
Можно использовать не обязательно память стека. Память можно изначально подготовить в куче, как это делает std::vector для своих элементов.
Зато приведённое решение позволяет сочетать динамическую типизацию и лёгкую замену имплементации (все данные спрятаны). Причём внешне программист работает с объектами по значению.
Какие милые детские мечты об идеальном 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, что сгоняет в кучу за памятью, а потом заполнит эту память объектом, который делает это быстрее чем просто заполнение памятью объектом без первого шага?

Information

Rating
Does not participate
Location
Ярославль, Ярославская обл., Россия
Date of birth
Registered
Activity

Specialization

Game Developer
Lead