#include <gsl/gsl>
void example() {
auto cleanup = gsl::finally([] {
// This will be called when the scope ends
std::cout << "Cleanup executed\n";
});
// ... do work ...
// cleanup will be called automatically here
}
И ещё. Мне, как читателю, было бы удобнее если бы статья была разделена на две: 1) туториал по созданию библиотеки; 2) сами алгоритмы на CPP (математика, кинематика и т.п.). Ещё раз спасибо за статью )
Но IMHO: Для туториала по созданию библиотеки не хватает раздела с Автотестами. Кроме того от библиотеки на GitHub-е, да ещё и с документацией и примерами, ожидаешь переносимости и возможности настраивать разные виды сборки (динамическая, статическая и т.п.). А это может повлиять и на структуру файлов и на сами исходники.
А на винде точность измерения разве не зависит от материнской платы и самой версии windows?
Это зависит от функции. Windows "загрубляет" дискретность ряда функций до 100ns, но если не может обеспечить и такую точность то, например, на старом 32-х битном Intel Atom Z2760@1.80GHz дискретность всех измеренных мной функций оказалась не лучше 570ns. Т.е. QueryPerformanceCounter при документированных единицах измерения 100ns смогла измерить интервал времени лишь в 5,7 раза длиннее. Такую же дискретность на этой машине выдали и все современные стандартные функции С и С++.
Многие ф-ии WinAPI (например GetSystemTime) завязаны на частоту прерывания системных часов которая по умолчанию равна 64 тикам в секунду независимо от железа, но может изменяться программно с помощью ExSetTimerResolution.
Кстати, частота прерывания системных часов может изменяться, например, музыкальным или видео плеером, что иногда приводит к неприятным сюрпризам.
Наверно, на всех машинах установлен как минимум MS Sandbox. Но для меня неожиданно, что включение Hyper-V влияет на процессы запущенные прямо на хосте, а не в VM.
IMHO с такими задержками CPUID для профилирования не годится. Но если погуглить RDTSC, то чаще всего для сериализации инструкций предлагают именно его.
Мой коммент относился к: voidfunction(std::unique_ptr<A>(new A()), std::unique_ptr<B>(new B())) { ... } "Предположим, что new A() выполняется успешно, но new B() выбрасывает исключение: вы ловите его, чтобы возобновить нормальное выполнение программы. К сожалению, стандарт C++ не требует, чтобы объект A был уничтожен, а его память высвобождена: память тихо утекает, и нет способа ее очистить." IMHO в C++17 компилятор не имеет право перемешивать этапы инициализации параметров ф-ии. "In a function call, value computations and side effects of the initialization of every parameter are indeterminately sequenced with respect to value computations and side effects of any other parameter." [ Order of evaluation - cppreference.com ] Поэтому описанная утечка памяти не произойдёт и использование make_shared/make_unique в этом случае не обязательно.
Бывает надо передать в shared_ptr указатель без права владения. В этом случае тоже помогает aliasing constructor, но не уверен, что здесь нет нарушения какого-нибудь правила стандарта. Может кто прокомментировать следующий код?
Ещё хочу напомнить про незаслуженно забытый aliasing constructor для shared_ptr. Это мегафича позволяющая shared_ptr-у ссылаться и владеть совершенно разными объектами! Часто требуется передать указатель на часть чего-то большего, и при этом гарантировать, что это большее не удалится, пока мы работаем с его частью, shared_ptr позволяет это.
Вроде проблема с утечкой памяти была исключена ещё в C++17. Единственная причина использовать make_shared это экономия ресурсов (и то не всегда). А в чём преимущества make_unique?
Guideline Support Library (GSL)
Авторы: Бьярне Страуструп, Херб Саттер, Нил Макалистер.
Некоторые идеи уже перекочевали в стандарт C++ (std::span (C++20) - аналог gsl::span, std::byte (C++17) - похожая идеология с gsl::byte).
Реализация gsl::finally у MS (GSL/include/gsl/util at main · microsoft/GSL · GitHub) - 28 строк. Пример использования.
И ещё. Мне, как читателю, было бы удобнее если бы статья была разделена на две:
1) туториал по созданию библиотеки;
2) сами алгоритмы на CPP (математика, кинематика и т.п.).
Ещё раз спасибо за статью )
Респект за статью!
Но IMHO:
Для туториала по созданию библиотеки не хватает раздела с Автотестами.
Кроме того от библиотеки на GitHub-е, да ещё и с документацией и примерами, ожидаешь переносимости и возможности настраивать разные виды сборки (динамическая, статическая и т.п.). А это может повлиять и на структуру файлов и на сами исходники.
Но привычный порядок на два символа короче ):
"0123456789ABCDEF"[(n >> i)%16]
Интересно!
Прогнал утилиту на VPS под KVM:
Частота процессора в два раза ниже, и время в два раза больше.
Согласен, наверно слово resolution подошло бы лучше.
Это зависит от функции. Windows "загрубляет" дискретность ряда функций до 100ns, но если не может обеспечить и такую точность то, например, на старом 32-х битном Intel Atom Z2760@1.80GHz дискретность всех измеренных мной функций оказалась не лучше 570ns. Т.е. QueryPerformanceCounter при документированных единицах измерения 100ns смогла измерить интервал времени лишь в 5,7 раза длиннее. Такую же дискретность на этой машине выдали и все современные стандартные функции С и С++.
Многие ф-ии WinAPI (например GetSystemTime) завязаны на частоту прерывания системных часов которая по умолчанию равна 64 тикам в секунду независимо от железа, но может изменяться программно с помощью ExSetTimerResolution.
Кстати, частота прерывания системных часов может изменяться, например, музыкальным или видео плеером, что иногда приводит к неприятным сюрпризам.
Не зря надеялся )
Наверно, на всех машинах установлен как минимум MS Sandbox. Но для меня неожиданно, что включение Hyper-V влияет на процессы запущенные прямо на хосте, а не в VM.
IMHO с такими задержками CPUID для профилирования не годится. Но если погуглить RDTSC, то чаще всего для сериализации инструкций предлагают именно его.
Мой коммент относился к:
void function(std::unique_ptr<A>(new A()), std::unique_ptr<B>(new B())) { ... }
"Предположим, что new A() выполняется успешно, но new B() выбрасывает исключение: вы ловите его, чтобы возобновить нормальное выполнение программы. К сожалению, стандарт C++ не требует, чтобы объект A был уничтожен, а его память высвобождена: память тихо утекает, и нет способа ее очистить."
IMHO в C++17 компилятор не имеет право перемешивать этапы инициализации параметров ф-ии.
"In a function call, value computations and side effects of the initialization of every parameter are indeterminately sequenced with respect to value computations and side effects of any other parameter." [ Order of evaluation - cppreference.com ] Поэтому описанная утечка памяти не произойдёт и использование make_shared/make_unique в этом случае не обязательно.
Бывает надо передать в shared_ptr указатель без права владения. В этом случае тоже помогает aliasing constructor, но не уверен, что здесь нет нарушения какого-нибудь правила стандарта.
Может кто прокомментировать следующий код?
https://godbolt.org/z/x6n6aGrxc
Ещё хочу напомнить про незаслуженно забытый aliasing constructor для shared_ptr.
Это мегафича позволяющая shared_ptr-у ссылаться и владеть совершенно разными объектами! Часто требуется передать указатель на часть чего-то большего, и при этом гарантировать, что это большее не удалится, пока мы работаем с его частью, shared_ptr позволяет это.
Вроде проблема с утечкой памяти была исключена ещё в C++17.
Единственная причина использовать make_shared это экономия ресурсов (и то не всегда). А в чём преимущества make_unique?