4 ms·
This is cursed: https://github.com/es3n1n/defendnot/blob/master/defendnot-loader/core/autorun.cpp#L28C1-L30C15 https://github.com/es3n1n/defendnot/blob/master/
by raptorfactor 1y ago
This is cursed:
https://github.com/es3n1n/defendnot/blob/master/defendnot-loader/core/autorun.cpp#L28C1-L30C15 https://github.com/es3n1n/defendnot/blob/master/defendnot-lo...
If you're curious what's actually going on there:
https://github.com/es3n1n/defendnot/blob/master/cxx-shared/shared/defer.hpp https://github.com/es3n1n/defendnot/blob/master/cxx-shared/s...
- es3n1n 1y agoyeah sorry i didnt feel like implementing my own RAII stuff for all the COM thingies due to time constraints. it will be changed in the next update though
- junon 1y agoHonestly if this isn't part of a public API this isn't very cursed in terms of C++, especially if you have a lot of one-off cleanup operations. I think the only bit I don't like personally is the syntax. I normally implement defer as a macro to keep things clean. If done correctly it can look like a keyword: `defer []{ something(); };`.
- quietbritishjim 1y agoI think the syntax is exactly why they're saying it's cursed. IMO your suggestion is no better - yes it makes defer look like a keyword, but it's not! As I said in a sibling comment, I think it's clearer if you're honest that you're using a macro: DEFER([](){something();}); Or you could even make a non-macro version (but then you need to think of variable names for each defer): auto defer_uninitialise = do_defer([](){CoUninitialize();});
- junon 1y agoSure, I've used __LINE__ for this before too, and yeah I agree that my keyword construction was too clever (seemed cool at the time, since the macro had a dangling = at the end to make it work).
- es3n1n 1y agohttps://github.com/es3n1n/defendnot/pull/6 https://github.com/es3n1n/defendnot/pull/6
- Asooka 1y agoWhy did you write it with two structs though? You could do #define defer(body) DeferHolder COMMON_CAT(_defer_instance, __LINE__) {([&]()->void body)}; and call it as defer({ function body here; }); Which looks much nicer. The preprocessor treats balanced curlies as one single token regardless of how many lines it spans, precisely to enable this usage.
- gavinray 1y agohttps://en.cppreference.com/w/cpp/experimental/scope_exit https://en.cppreference.com/w/cpp/experimental/scope_exit scope_exit{[&]{ ... } };
- chii 1y agocan someone well versed in explaining CPP magic explain what is going on and why it is cursed?
- quietbritishjim 1y agoWe're starting with this code: defer->void { CoUninitialize(); }; Using the macros in the second linked file, this expands to: auto _defer_instance_1234 = Defer{} % [&]()->void { CoUninitialize(); }; * The 1234 is whatever the line number is, which makes the variable name unique. * auto means infer the type of this local variable from the expression after the =. * Defer{} means default construct a Defer instance. Defer is an empty type, but it allows the % following it to call a specific function because... * Defer has an overloaded operator%. It's a template function, which takes a callable object (type is the template parameter Callable) and returns a DeferHolder<Callable> instance. * [&]()->void { /*code here*/ }; is C++ syntax for a lambda function that captures any variables it uses by address (that's the [&] bit), takes no parameters (that's the () bit) and returns nothing (that's the ->void bit). The code goes in braces. * DeferHolder calls the function it holds when it is destroyed. It's subjective but some (including me!) would say it's cursed because it's using a macro to make something that almost looks like C++ syntax but isn't quite. I'm pretty confident with C++ but I had no idea what was going on at first (except, "surely this is using macros somehow ... right?"). [Edit: After some thought, I think the most confusing aspect is that defer->void looks like a method call through an object pointer rather than a trailing return type.] I'd say it would be better to just be honest about its macroness, and also just do the extra typing of the [&] each time so the syntax of the lambda is all together. (You could then also simplify the implementation.) You end up with something like this: DEFER([&]()->void { CoUninitialize(); }); Or if you go all in with no args lambda, you could shorten it to: DEFER({ CoUninitialize(); });
- chii 1y agoThat's interesting! So i assume that this macro allows code to get registered to be run after the 'current' scope exits. But from my understanding (or lack thereof), the `auto _defer_instance_1234 =` is never referenced post construction. Why doesn't the compiler immediately detect that this object is unused and thus optimize away the object as soon as possible? Is it always guaranteed that the destructor gets called only after the current scope exits?
- fc417fc802 1y agoWhat's cursed about this? I use this pattern all over in my code although the signature at the callsite looks a bit different (personal preference). D (for example) has the concept of statements that trigger at end of scope built into the language.
- drabbiticus 1y agoCode is a way you treat your coworkers - Michael Feather, https://x.com/mfeathers/status/1031176879577780224 https://x.com/mfeathers/status/1031176879577780224 TL;DR, not AI The code defers a function call until the point in time that an object goes out of scope. The implementation uses C macros to create a more succinct syntax that omits parts of the necessary C lambda/unnamed function definition and to create a unique variable name for managing the deferred function call. However, the resulting syntax eschews the common convention of using UPPER CASE to denote C macros, and instead appears similar at first glance to a function call from an object pointer. This can cause confusion if one is not familiar with this pattern and expects macros to be communicated differently. Some commenters say this is common enough, or useful enough to them, to be considered almost idiomatic in some contexts. For technical explanation, https://news.ycombinator.com/item?id=43959403#43960905 https://news.ycombinator.com/item?id=43959403#43960905 provides a useful breakdown of how the macro works.