Однако void* не является object pointer type.
Если не ошибаюсь, по стандарту каст между object pointer и void pointer может выполняться только со static_cast, хотя по факту любой компилятор reinterpret_cast тоже съест.
Я вообще не пишу на Rust, только интересуюсь :)
Как мне кажется, выделение unsafe блоков — как раз очень полезная с точки зрения безопасности фича. А мой комментарий выше — контраргумент к Вашему утверждению, что Rust безопасен тем, что UB проявляется (не)определённым образом.
В C++ тоже сплошь и рядом UB проявляется гораздо позже, чем происходит. Например, у нас недавно был случай, когда приложение начинало зависать через пару часов работы после того, как объект был удалён по указателю на интерфейс, в котором не было виртуального деструктора.
Интересно, о чём будет думать программист, который напишет свой enum class no, в расчёте на то, что с ним будет другой результат? Или Вы имеете в виду, что символ no может чисто случайно оказаться в том же scope, и программист воспользуется им, не посмотрев?
В каком-то смысле да, но для программиста выглядит ближе к многопоточной парадигме, в частности доступно ветвление кода внутри потока (реализуется выполнением обеих ветвей и применением маски).
А в NVIDIA Volta планировщик уже даже может при необходимости разделять потоки и вести для каждого отдельный стек и счётчик инструкций. Оптимизацией под Volta я пока не занимался, так что не могу сказать, насколько сильно это в реальности меняет подход к программированию.
Поправка по поводу GPU: большинство современных видеокарт (NVIDIA, AMD, ARM Mali) используют модель SIMT (Single Instruction, Multiple Threads), а не SIMD. Что не отменяет того факта, что алгоритмы для них нужны другие, чем для CPU общего назначения, и, соответственно, набор эффективно решаемых задач на CPU и GPU не совпадает.
Если делить на активов и пассивов, получается изначальная «гетеросексуальная» задача. Если добавлять универсалов, есть два варианта:
1) Пара может состоять из двух универсалов. Тогда в общем случае задача неразрешима (доказывается тем же самым примером).
2) Универсалы могут составлять пару только активам/пассивам. Тогда задача представляется немного по-другому, появляются три группы A, P, U из которых надо составить равновесное множество пар вида (a p), (a u) или (p u). Кажется, что эта задача тоже должна решаться слегка изменённой процедурой Гейла-Шепли.
Всё верно, в статье ошибки нет. Рассмотрим возможные комбинации партнёров: ab cd (1), ac bd (2), ad bc (3).
1) b предпочитает c своему партнёру a, c тоже предпочитает a по сравнению с d. Пары распадаются, переходят в состояние (3).
2) a предпочитает b своему партнёру c, b тоже предпочитает a по сравнению с d. Пары распадаются, переходят в состояние (1).
3) c предпочитает a своему партнёру b, a тоже предпочитает c по сравнению с d. Пары распадаются, переходят в состояние (2).
Да, извиняюсь, немного запутался. void* не является pointer-to-object type, но является object pointer type.
Тогда reinterpret_cast<void*> и reinterpret_cast<void**> полностью валидны.
Однако void* не является object pointer type.
Если не ошибаюсь, по стандарту каст между object pointer и void pointer может выполняться только со static_cast, хотя по факту любой компилятор reinterpret_cast тоже съест.
У нас повсеместно используются смарт-поинтеры, а эта проверка видимо недостаточно умная, чтобы ругнуться на деструктор unique_ptr.
gcc 9.1.0
С -Wnon-virtual-dtor действительно ловит, -Wall -Wextra -Wpedantic оказывается недостаточно.
Во-первых, мне почему-то ни gcc -Wall -Wextra -Wpedantic, ни даже clang-tidy ничего не сказали, а во-вторых мой комментарий был вообще не об этом.
Я вообще не пишу на Rust, только интересуюсь :)
Как мне кажется, выделение unsafe блоков — как раз очень полезная с точки зрения безопасности фича. А мой комментарий выше — контраргумент к Вашему утверждению, что Rust безопасен тем, что UB проявляется (не)определённым образом.
С моей точки зрения это наоборот, жирный минус к безопасности. UB именно тем и плох, что проявляется в неожиданные моменты и тяжело отлавливается.
В C++ тоже сплошь и рядом UB проявляется гораздо позже, чем происходит. Например, у нас недавно был случай, когда приложение начинало зависать через пару часов работы после того, как объект был удалён по указателю на интерфейс, в котором не было виртуального деструктора.
У меня так (time из zsh):
1) Запускал через bash, потому что zsh отказывается замерять время работы echo напрямую
2) Тоже пришлось устанавливать
3)
4) Ожидаемо сильно страдает от большого числа вложенных директорий
5)
6)
7)
rsync
ls
Мне кажется или в вариантах с глобами правильнее делать
time bash -c '...'
, чтобы время разворачивания глобов тоже учитывалось?Интересно, о чём будет думать программист, который напишет свой enum class no, в расчёте на то, что с ним будет другой результат? Или Вы имеете в виду, что символ
no
может чисто случайно оказаться в том же scope, и программист воспользуется им, не посмотрев?Q — рациональные числа, IEEE 754 ассоциировать с каким-то алгебраическим множеством неразумно.
Это достаточно узкоспециализированная вещь, обычно для этого существуют специальные библиотеки.
В nim можно объявить несколько переменных одного типа как
var a, b, c: int
Ещё способ с включенной Compose Key: Compose,",U.
В каком-то смысле да, но для программиста выглядит ближе к многопоточной парадигме, в частности доступно ветвление кода внутри потока (реализуется выполнением обеих ветвей и применением маски).
А в NVIDIA Volta планировщик уже даже может при необходимости разделять потоки и вести для каждого отдельный стек и счётчик инструкций. Оптимизацией под Volta я пока не занимался, так что не могу сказать, насколько сильно это в реальности меняет подход к программированию.
Поправка по поводу GPU: большинство современных видеокарт (NVIDIA, AMD, ARM Mali) используют модель SIMT (Single Instruction, Multiple Threads), а не SIMD. Что не отменяет того факта, что алгоритмы для них нужны другие, чем для CPU общего назначения, и, соответственно, набор эффективно решаемых задач на CPU и GPU не совпадает.
Только (u u) пары — частный случай задачи с четырьмя группами, а значит эта задача в общем случае не имеет решения.
Если делить на активов и пассивов, получается изначальная «гетеросексуальная» задача. Если добавлять универсалов, есть два варианта:
1) Пара может состоять из двух универсалов. Тогда в общем случае задача неразрешима (доказывается тем же самым примером).
2) Универсалы могут составлять пару только активам/пассивам. Тогда задача представляется немного по-другому, появляются три группы A, P, U из которых надо составить равновесное множество пар вида (a p), (a u) или (p u). Кажется, что эта задача тоже должна решаться слегка изменённой процедурой Гейла-Шепли.
Всё верно, в статье ошибки нет. Рассмотрим возможные комбинации партнёров: ab cd (1), ac bd (2), ad bc (3).
1) b предпочитает c своему партнёру a, c тоже предпочитает a по сравнению с d. Пары распадаются, переходят в состояние (3).
2) a предпочитает b своему партнёру c, b тоже предпочитает a по сравнению с d. Пары распадаются, переходят в состояние (1).
3) c предпочитает a своему партнёру b, a тоже предпочитает c по сравнению с d. Пары распадаются, переходят в состояние (2).