Как стать автором
Обновить
10
0
Толкун Аркадий @destman

Пользователь

Отправить сообщение
На youtube есть канал Геоэнергетика. Ведущий — Борис Леонидович Марцинкевич. В одном из роликов, посвященных серии БН, было сказано что на этих АЭС нарабатывается энергетический плутоний а не оружейный. Разница между оружейным и энергетическим — изотопный состав. В энергетическом один из изотопов сильно не стабильный и не годится для вояк…
Поэтому от МАГАТЭ к этим АЭС претензий по поводу плутония нет.
Об этом и было мое сообщение. В таких случаях безопаснее использовать memcpy а не каст. Оно решает проблему выравнивания.
Стандарт явно не описывает размеры float, double, long double. Есть только определение что точность long double выше double и точность double выше float.
И в совсем общем случае каст в int любого размера (как и memcpy) даст неопределенное поведение.
Поэтому «Каст double к int64_t не может вызвать проблем с выравниванием» справедливо только в частном случае когда размер double равен 8 байт.
В какой части кода ошибка: в функции foo(double *bar) или в функции что ее вызывает?
И да в некоторых случаях foo(double *bar) может ожидать что адрес не выравненный.
Пример:
template<class Type, class Ptr>
Type readUnaligned(Ptr *ptr) {
Type rv;
memcpy(&rv, ptr, sizeof(Type));
return run
}
Что вам запрещает записать double в бинарный файл со смещением 123?
Пример: читаем данные из файла. Сделали mmap. Адрес не выровнен и тип указателя из которого читаем вполне может быть int64_t…
И даже больше скажу я ловил креши из-за этого UB. На старых arm процессорах которые не умеют читать по не выровненному адресу…
Так что да memcpy оно более безопасно. В релизе (-O3) оно все равно упрощается до нескольких инструкций (если это безопасно)
Немного практических примеров когда такое нужно:
1) Объект состоит из геометрии (ее не надо хранить всегда, после объединения в батчи выкидывается) и из атрибутов. Атрибутов может быть много они часто повторяются и некоторые нужны после обработки. Сами атрибуты могут быть не большими (особенно числа) и оверхед от shared_ptr существенно увеличит использование памяти.

2) вычисление стиля прорисовки объекта подразумевает много работы над атрибутами. Причём многие действия не создают новые атрибуты а выбирают из уже существующих (например выбрать из возможных локализаций нужный текст или выбрать из набора цветов один нужный). И тут мои замеры показывали что shared_ptr копирует себя медленнее чем вариант без поддержки слабых ссылок. И причина очевидна — shared_prt для копии надо записать 2 указателя и увеличить счётчик, тогда мое самописанное без поддержки слабых ссылок — 1 указатель и увеличить счётчик…

3) Есть набор пользовательских букмарок. Выбрав из всех букмарок те что видны — сделали кластеризацию. Букмарка по сути представляет из себя 2 координаты, ссылку на стиль прорисовки и ещё пару мелких флагов. Поэтому в памяти занимает не много но если для менеджмента использовать shared_ptr возникает очень большой оверхед. Эту самую кластеризацию нужно держать и на случай если надо проверить нажатие и для подготовки прорисовки и для поиска.

Как видите во всех случаях идёт работа с большим набором простых данных. Причём когда объект станет не нужным неизвестно…
К слову на iOS free работает примерно в 2 раза медленнее чем malloc. И до кучи блокирует free в других потоках…
Кастомные аллокаторы мы используем тоже.
Особенно весело получилось в триангуляции (когда надо полигон покрыть треугольниками чтоб можно было рисовать на GPU).
Вообще зная некоторые особенности данных (одинаковый размер, одинаковое время жизни, малое количество результатов на выходе итд) можно придумать решение с менеджментом памяти которе будет работать значительно быстрее стандартного. Этим и крут c++.
И да многие при оценке сложности работы алгоритма не учитывают, что работа с памятью не бесплатная…
Если вам интересно — подобный механизм управления памятью я использую в мобильном приложении Guru Maps. А конкретнее в подготовке векторных тайлов для прорисовки. Исходные данные такие: есть тайлы в которых может быть около 100000 объектов и стиль который определяет как это все рисовать. Если использовать стандартные подходы то на стареньком телефоне прожевать такое будет очень проблематично. В итоге приходится использовать всякие хитрые оптимизации:
— кастомный аллокатор при загрузке объектов. Никаких счетчиков тут не используется ибо даже они приводят к ощутимым педалям. А так как время жизни четко известно то и удалять все можно одной пачкой.
— те данные что должны получится на выходе (геометрия для прорисовки, высчитанные параметры и прочее) используют счетчики. Тут уже критичен оверхед по памяти. Ибо +-мебагайт памяти на тайл это уже не мало.
Да. Требует 2 функции — увеличить счетчик и уменьшить счетчик. Я такой подход применяю только в тех местах где нужна максимальная скорость и/или минимальный объем использованной памяти (а это почти всегда пишется на c++:)
Иными словами зачастую стандартный std::shared_ptr — содержит избыточные функции за которые платим скоростью и памятью…
Каждый объект содержит в себе счетчик. А умный указатель управляет этим счетчиком. В отличии от универсального решения — счетчик можно положить в любое место и уменьшить размер объекта в памяти. Из-за выравнивания часто получаем небольшой оверхед при наследовании или композиции. Этот небольшой оверхед может раздуть объект например с 16 байт до 24 (~30%)…
Именно по этой причине я не использую std::shared_ptr если слабые ссылки не нужны.
Самописанный умный указатель на атомарном счетчике (лежи в объекте) работает гораздо быстрее чем std::make_shared и кушает меньше памяти…
Тогда уж лучше remove_no_resize :)
Не сказал бы что так уж плохо все. В моей практике очень часто встречалась задача удалить некоторый набор данных из вектора а потом вставить в конец что-то новое. Если бы std::remove() сразу выполнял операцию erase то на один realloc могло быть больше в этом случае…
Если в вашем кастомном шрифте много глифов возможно проблема в поиске нужного глифа при подготовке текста к рендерингу.
Проверить что именно в этом проблема — замерять сколько времени работает CTLineCreateWithAttributedString с соответствующей строкой.
Если в глиф плохо оптимизирован (дизайнер натыкал 100500 точек) — то тоже может быть проблема в расчетах границ глифа (примерно чекнуть можно юзая CTLineGetImageBounds) + сама прорисовка может быть не быстрая (CTFontDrawGlyphs)…
Есть такая замечательная библиотека под именем Common Graphics Algorithms (CGAL). А в библиотеке есть функция bounded_side_2
Если полистать исходники — то можно понять как обрабатывать все граничные ситуации первого алгоритма.

А какже майнкрафт?
Не удивительно почему ява по умолчанию отсуствует в Lion/Snow Leopard.

Информация

В рейтинге
Не участвует
Откуда
Минская обл., Беларусь
Дата рождения
Зарегистрирован
Активность