From b121efbfbdb68ad376cda9740c7f657361907b21 Mon Sep 17 00:00:00 2001 From: Nekrolm Date: Sun, 26 May 2024 23:24:33 +0100 Subject: [PATCH] random_int_distribution and cleanups --- README.md | 57 +++++++++------- {syntax => standard_lib}/aligned_storage.md | 0 {syntax => standard_lib}/enable_if_void_t.md | 0 .../function_pass_and_address_restriction.md | 0 {syntax => standard_lib}/iostreams.md | 0 {syntax => standard_lib}/map_subscript.md | 0 .../null_terminated_string.md | 0 {syntax => standard_lib}/ranges_views_lazy.md | 0 .../shared_ptr_constructor.md | 0 {syntax => standard_lib}/stl_constructors.md | 0 standard_lib/uniform_int_distribution.md | 68 +++++++++++++++++++ 11 files changed, 100 insertions(+), 25 deletions(-) rename {syntax => standard_lib}/aligned_storage.md (100%) rename {syntax => standard_lib}/enable_if_void_t.md (100%) rename {syntax => standard_lib}/function_pass_and_address_restriction.md (100%) rename {syntax => standard_lib}/iostreams.md (100%) rename {syntax => standard_lib}/map_subscript.md (100%) rename {syntax => standard_lib}/null_terminated_string.md (100%) rename {syntax => standard_lib}/ranges_views_lazy.md (100%) rename {syntax => standard_lib}/shared_ptr_constructor.md (100%) rename {syntax => standard_lib}/stl_constructors.md (100%) create mode 100644 standard_lib/uniform_int_distribution.md diff --git a/README.md b/README.md index 3917f3c..8e0faa0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -# Ружье достаточной огневой мощи, чтобы на нем повеситься - -## Путеводитель C++ программиста по неопределенному поведению +# Путеводитель C++ программиста по неопределенному поведению #### *Паникуй!* @@ -51,27 +49,29 @@ 10. [Proxy-объекты и ссылки](lifetime/proxy_objects.md) 11. [use-after-move](lifetime/use-after-move.md) 12. [lifetime extension](lifetime/lifetime_extension.md) -5. Неработающий синтаксис и стандартная библиотека +5. (Не)работающий синтаксис 1. [Most Vexing Parse](syntax/most_vexing_parse.md) 2. [Const](syntax/const_launder.md) - 3. [Конструкторы контейнеров](syntax/stl_constructors.md) - 4. [std::move](syntax/move.md) - 5. [std::enable_if/std::void_t](syntax/enable_if_void_t.md) - 6. [Потерянный return](syntax/missing_return.md) - 7. [Эллипсис и функции с произвольным числом аргументов](syntax/c_variadic.md) - 8. [`operator[] ` ассоциативных контейнеров](syntax/map_subscript.md) - 9. [потоки ввода/вывода](syntax/iostreams.md) - 10. [`operator ,`](syntax/comma_operator.md) - 11. [function-try-block](syntax/function-try-catch.md) - 12. [Пустые структуры и типы нулевого размера](syntax/zero_size.md) - 13. [NULL-терминированные строки](syntax/null_terminated_string.md) - 14. [Конструирование std::shared_ptr](syntax/shared_ptr_constructor.md) - 15. [std::aligned_storage](syntax/aligned_storage.md) - 16. [(Не)явное приведение типов](syntax/explicit_but_implicit.md) - 17. [std::ranges::views](syntax/ranges_views_lazy.md) - 18. [функции стантарной библиотеки как параметры](syntax/function_pass_and_address_restriction.md) - 19. [Многомерный operator[]](syntax/multidimensional_subscript.md) -6. Исполнение программы + 3. [std::move](syntax/move.md) + 4. [Потерянный return](syntax/missing_return.md) + 5. [Эллипсис и функции с произвольным числом аргументов](syntax/c_variadic.md) + 6. [`operator ,`](syntax/comma_operator.md) + 7. [function-try-block](syntax/function-try-catch.md) + 8. [Пустые структуры и типы нулевого размера](syntax/zero_size.md) + 9. [(Не)явное приведение типов](syntax/explicit_but_implicit.md) + 10. [Многомерный operator[]](syntax/multidimensional_subscript.md) +6. Стандартная библиотека + 1. [NULL-терминированные строки](standard_lib/null_terminated_string.md) + 2. [Конструирование std::shared_ptr](standard_lib/shared_ptr_constructor.md) + 3. [потоки ввода/вывода](standard_lib/iostreams.md) + 4. [std::aligned_storage](standard_lib/aligned_storage.md) + 5. [функции стантарной библиотеки как параметры](syntax/function_pass_and_address_restriction.md) + 6. [std::ranges::views](standard_lib/ranges_views_lazy.md) + 7. [`operator[] ` ассоциативных контейнеров](standard_lib/map_subscript.md) + 8. [std::enable_if/std::void_t](standard_lib/enable_if_void_t.md) + 9. [Конструкторы контейнеров](standard_lib/stl_constructors.md) + 10. [std::uniform_int_distribution](standard_lib/uniform_int_distribution.md) +7. Исполнение программы 1. [Бесконечные циклы](runtime/endless_loop.md) 2. [Рекурсия](runtime/recursion.md) 3. [Ложный noexcept](runtime/noexcept.md) @@ -89,10 +89,10 @@ 15. [Невиртуальные виртуальные функции](runtime/virtual_functions.md) 16. [Variable length array](runtime/vla.md) 17. [ODR violation и разделяемые библиотеки](runtime/dll_and_odr_violation.md) -7. Происхождение указателей +8. Происхождение указателей 1. [Невалидные указатели](pointer_prominence/invalid_pointer.md) 2. [Placement `operator new[]`](pointer_prominence/array_placement_new.md) -8. Параллелизм +9. Параллелизм 1. [Race condition](concurrency/race_condition.md) 2. [shared_ptr](concurrency/shared_ptr.md) 3. [thread::join](concurrency/jthread.md) @@ -116,4 +116,11 @@ **Нельзя** использовать в платных сервисах или взимать плату за обучение по этим материалам. -_Copyright 2020-2024 Dmitry Sviridkin_ +#### Ну и самое последнее примечание + +Черновое название этой работы, "Ружье достаточной огневой мощи, чтобы на нем повеситься", как могли догадаться искушенные читатели, было эдаким реверансом в сторону известного (но очень плохо состарившегося) сборника по C++ "Веревка достаточной длины, чтобы выстрелить себе в ногу" от Алана Голуба. Но, к сожалению, мы живем в нежном мире победивших алгоритмов ранжирования и надзорных органов, то и дело стремящихся кого-нибудь от чего-нибудь защитить. + +Автор, конечно, очень бы хотел защитить всех от C++, и именно этому и служит данных сборник, но с заблокированным и пессимизированным репозиторием прогресса в этом направлении не будет. + + +_Copyright 2020-2024 Dmitry Sviridkin_ \ No newline at end of file diff --git a/syntax/aligned_storage.md b/standard_lib/aligned_storage.md similarity index 100% rename from syntax/aligned_storage.md rename to standard_lib/aligned_storage.md diff --git a/syntax/enable_if_void_t.md b/standard_lib/enable_if_void_t.md similarity index 100% rename from syntax/enable_if_void_t.md rename to standard_lib/enable_if_void_t.md diff --git a/syntax/function_pass_and_address_restriction.md b/standard_lib/function_pass_and_address_restriction.md similarity index 100% rename from syntax/function_pass_and_address_restriction.md rename to standard_lib/function_pass_and_address_restriction.md diff --git a/syntax/iostreams.md b/standard_lib/iostreams.md similarity index 100% rename from syntax/iostreams.md rename to standard_lib/iostreams.md diff --git a/syntax/map_subscript.md b/standard_lib/map_subscript.md similarity index 100% rename from syntax/map_subscript.md rename to standard_lib/map_subscript.md diff --git a/syntax/null_terminated_string.md b/standard_lib/null_terminated_string.md similarity index 100% rename from syntax/null_terminated_string.md rename to standard_lib/null_terminated_string.md diff --git a/syntax/ranges_views_lazy.md b/standard_lib/ranges_views_lazy.md similarity index 100% rename from syntax/ranges_views_lazy.md rename to standard_lib/ranges_views_lazy.md diff --git a/syntax/shared_ptr_constructor.md b/standard_lib/shared_ptr_constructor.md similarity index 100% rename from syntax/shared_ptr_constructor.md rename to standard_lib/shared_ptr_constructor.md diff --git a/syntax/stl_constructors.md b/standard_lib/stl_constructors.md similarity index 100% rename from syntax/stl_constructors.md rename to standard_lib/stl_constructors.md diff --git a/standard_lib/uniform_int_distribution.md b/standard_lib/uniform_int_distribution.md new file mode 100644 index 0000000..ce23fc0 --- /dev/null +++ b/standard_lib/uniform_int_distribution.md @@ -0,0 +1,68 @@ +# Нельзя так просто взять и сгенерировать случайную последовательность байт + +В C++11 стандартная библиотека пополнилась многими отличными штуками, в том числе функциями и классами для работы с генераторами случайных чисел удобным и, как это ни странно, предсказуемым способом: + +В наследство от C, С++ досталась функция `rand()`, которой на сегодняшний день не рекомендуется пользоваться нигде, кроме как совершенно игрушечных проектах: +- Если ее `seed` не инициализировать через `srand()`, он будет инициализирован, внезапно, единицей (а могли бы взять 42) +- Естественно она использует некий глобальное, возможно, thread local состояние. Это impementation defined +- В многопоточной среде thread safety тоже implementation defined. +В общем, очень непредсказуемая штука! + +Другое дело функционал из `#include `! + +Вот вам и разные генераторы, и преобразования функций распределения, и вы их можете друг от друга отделять и иметь свой собственный, особенно инициализированный генератор для каждой отдельной сущности в вашем проекте, и многопоточный доступ организовывайте как хотите. Красота! + +А давайте сгенерируем последовательность случайных, равномерно распределенных байт. + +```C++ +#include +#include + +int main() +{ + std::random_device rd; // a seed source for the random number engine + std::mt19937 gen(rd()); // mersenne_twister_engine seeded with rd() + std::uniform_int_distribution distrib{}; // don't try to use std::byte! it won't compile + + // Use distrib to generate random byte + for (int n = 0; n != 10; ++n) + std::cout << int32_t(distrib(gen)) << ' '; // we need a cast to print numeric values instead of characters + std::cout << '\n'; +} +``` +Компилируем, запускаем, все [отлично работает](https://godbolt.org/z/xh1bY7PTq)!.. +По крайней мере c GCC и Clang. + +А что если нам нужна кроссплатформенная сборка в том числе под Windows с помощью MSVC?... А давайте попробуем просто взять и скомпилировать как есть... + +[Ой](https://godbolt.org/z/Ka93s7sW6) + +``` +example.cpp +C:/data/msvc/14.39.33321-Pre/include\random(2107): error C2338: static_assert failed: 'invalid template argument for uniform_int_distribution: N4950 [rand.req.genl]/1.5 requires one of short, int, long, long long, unsigned short, unsigned int, unsigned long, or unsigned long long' +C:/data/msvc/14.39.33321-Pre/include\random(2107): note: the template instantiation context (the oldest one first) is +(9): note: see reference to class template instantiation 'std::uniform_int_distribution' being compiled +C:/data/msvc/14.39.33321-Pre/include\random(2107): error C2338: static_assert failed: 'note: char, signed char, unsigned char, char8_t, int8_t, and uint8_t are not allowed' +Compiler returned: 2 +``` + +Ну-у, матерый разработчик, знакомый со причудами старых версий MSVC, который с по умолчанию включенным `\permissive+` мог компилировать совершенно безумные вещи, не сильно удивится и скажет, что опять Microsoft какую-то ерунду придумали просто... + +Удивительно, `но нет`(https://eel.is/c++draft/rand#req.genl-1.6)! + +``` +Throughout this subclause [rand], the effect of instantiating a template: +... +that has a template type parameter named UIntType is undefined unless the corresponding template argument is cv-unqualified and is one of unsigned short, unsigned int, unsigned long, or unsigned long long. +``` + +Подставлять `uint8_t` в `std::uniform_int_distribution` стандартом не разрешается под стахом неопределенных эффектов. + +Это, конечно, совершенно нелепо, и в 2013 году даже поднимался вопрос о принятии [defect report](https://cplusplus.github.io/LWG/issue2326), но его отклонили как not a defect и предложили написать proposal в стандарт, чтобы как-то это дело исправить... В общем по состоянию на 2024 год не исправили. Возможно, исправят в C++26. Или в C++29. + +Кстати, на всякий случай, `__int128_t` тоже использовать как бы нельзя. [Хотя с GCC работает.](https://godbolt.org/z/9Mxrx6aEr) + +# Полезные ссылки +1. [Обсуждение на reddit](https://www.reddit.com/r/cpp/comments/1czwa5h/is_instantiating_stduniform_int_distributionuint8/) +2. [cppreference uniform_int_distribution](https://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution) +