7 ms·
The idiomatic way to do that is with destructors. EDIT: Sorry for the confusion, I misread the article and thought this was about C++2x.
by majewsky 8y ago
The idiomatic way to do that is with destructors.
EDIT: Sorry for the confusion, I misread the article and thought this was about C++2x.
- mouldysammich 8y agoC doesn't have destructors, does it?
- vkazanov 8y agoYeah... Actually adding something like defer {...clean up code...} would be really nice. But who are we to ask..? Just programmers, i.e. mere mortals nobody really cares about. :-)
- stinos 8y agoYou can use C++ as some kind of C with destructors though :P Scoped cleanup is really a nice thing.. But then you also want templates of course to get rid of your void*. And oh, wait, what's that? A cross-platform thread implementation (well, sort of, depends on platform)? A string thing which I can search without strstr? Anonymous functions which capture? Auto? Gimme gimme :]
- beefhash 8y ago> You can use C++ as some kind of C with destructors though :P Scoped cleanup is really a nice thing.. C++ is not a strict superset of C. You actually have to cast void pointers, for example. > But then you also want templates of course to get rid of your void*. No, actually, I think I can live without that, but thank you. > And oh, wait, what's that? A cross-platform thread implementation (well, sort of, depends on platform)? C11, threads.h. Been there, got that. > A string thing which I can search without strstr? Okay, I'll give you that, string handling is hell. > Anonymous functions which capture? Have their uses, but I'm not sure if C is really the right place for it. > Auto? auto (as used in C++11 and later) is a solution in need of a problem in C. When you don't have piles of templates and iterators, you also tend not to need to automatically derive types. In a world where signed/unsigned integer comparison can have fatal consequences, you probably do want to be very sure about your types.
- rubber_duck 8y ago>C++ is not a strict subset of C. I think you flipped this :) ?
- stinos 8y ago> C++ is not a strict superset of C. I know that. I use both C and C++ practically daily. The post was partly joking. But only partly (for example of course I could live without templates if really needed but seriously they make some jobs a lot better and easier). Hence I aptly phrased it some kind of C hoping (idly it seems) no one would trip over it because it's obviously not C.
- Dylan16807 8y agoI don't think those other features are half as compelling as you think they are.
- stinos 8y agoUsing both C and C++, each in their place, I actually do think they are.
- Dylan16807 8y agoThen why ever use C if they're that compelling? I'm not really understanding how wanting one little thing from C++ implies diving all the way in.
- stinos 8y agoThen why ever use C Because some platforms I've used it on did't have proper C++ support. Or because a project I contribute to is already written in C. Or because of limited resources. Etc. I'm not really understanding how wanting one little thing from C++ implies diving all the way in. It's just an example of a possible train of thought. And I wouldn't call something like templates 'one little thing'. So suppose there's a choice between both, and no limit on resources etc, and I could go for everything C but templates could make everything easier then just going for C++ instead is an option. Even when not going 'all in' and writing what looks like standard C + template support.
- Dylan16807 8y ago> And I wouldn't call something like templates 'one little thing'. Agreed. But templates aren't the one little thing, they're something you said would be 'next'. The 'one little thing' is a way to replace the GOTOs used for releasing resources. I think it's an easy argument that when people are repeatedly building a pattern out of GOTO, there's a gap in the control flow tools that a language gives you.
- maxxxxx 8y agoSometimes I wonder if a C++ without inheritance would be the right thing. All the crazy design abuses I have seen were around inheritance. Other things like auto and anonymous functions are just super useful and I wouldn't want to miss them.
- jfoutz 8y agoAuto is already taken in C. It’s the default, rather than register or static, so you hardly ever see it
- kazinator 8y agoauto was taken in exactly the same way in C++ until fairly recently. They re-purposed it because it was obsolescent. auto was already in vanishing disuse in C at the time ANSI C came out in 1989. The C++ use of auto resurrects an aspect of the way auto was used in the C predecessor languages B and NB. In these pre-C languages, everything was an integer cell. A declaration of local variables looked like this: auto x, y; the auto meant automatic storage (stack), but the real purpose here is syntactic: the auto is a declaration specifier, which makes the above construct a declaration. There is no indication of type, because it is implicit. Without the auto it would look like a comma expression with no effect. This implicit typing survived into C for "implicit int" return values, like "main () {...}". But type specifiers were introduced and became mandatory in declarations, and so auto became unnecessary verbiage since all it did now was specify a storage class that was already the default one. C++ resurrect the syntactic use of auto in a way: once again, it provides declaration syntax that allows the type specifier to be omitted. This time, of course, that type is inferred rather than assumed integer.
- jfoutz 8y agoThis is a great thoughtful reply to my terse, shallow comment. Thank you. It’s insightful
- shaklee3 8y agoNot the language, but some compilers have something similar: https://stackoverflow.com/questions/2053029/how-exactly-does-attribute-constructor-work https://stackoverflow.com/questions/2053029/how-exactly-does...
- Aardwolf 8y agoYep, talking about C here, not C++. If they would add that feature, you could use macros to get constructor and destructor like behavior (as long as it's within the same scope, you could write a macro that constructs your object, and in addition contains something like "at scope exit: run this function"), which would be super useful and as far as I'm aware not very complex for the compiler (as all they have to do is run some code whenever exiting scope) nor very far outside of the spirit of C (it's still very low level, just a small convenience feature with interesting implications, especially when used with macros).
- kazinator 8y agoC++ is a dialect of C. It is the result of starting with C, and then accommodating a massive, sustained sequence of feature requests, exactly like ones we are seeing in this thread. Everyone thinks that if just their pet feature request is added to C and everyone else's ideas are rejected, it will still be C.
- bunderbunder 8y agoC++ is more than that; it's a set of additional features that create something of a C-flavored multiparadigm language. Which inevitably does turn it into a kitchen sink language, since it's trying to be all things to all people. This idea doesn't seem to be in that spirit to me. It's not trying to do something radical like, say, adding OOP semantics to C. It's suggesting that C, a structured programming language, get a feature designed to improve the ergonomics for people doing structured programming in C.
- MaxBarraclough 8y agoBrief aside: Boost has a facility for doing this in C++ without declaring a new class. (It boils down to a destructor, but it's more compact.) https://www.boost.org/doc/libs/release/libs/scope_exit/doc/html/index.html https://www.boost.org/doc/libs/release/libs/scope_exit/doc/h...
- aaaaaaaaaab 8y agoBoost.ScopeExit does declare a new class via macros.
- MaxBarraclough 8y agoYes, and I hinted at this, but it's more compact.
- nwallin 8y agoDo they have a new version based on lambdas? The syntax of that is painful. I splatter my code with this: // WTFPL class Finally { std::function<void()> f; public: Finally(std::function<void()> f) : f{f} {} ~Finally() {f();} void disable() { f = [](){}; } }; Which looks much prettier: socket* s = open_socket(); // or whatever Finally cleanup_socket{[](){ close_socket(s);}}; // optionally, to keep it alive: cleanup_socket.disable(); Am typing on mobile. No guarantees about syntax errors. I still need to look into where the right places to put r value references and/or std::move are, but for the most part, I never put anything other than a pointer in the closure so I'm not worried about copy constructor cost.
- Matthias247 8y agoHowever your implementation based on std::function might allocate, which is then non-zero cost compared to normal exit statements. Better directly store the lambda inside the class, which requires that to be generic (Finally<LambdaType>). That can be hidden by using the class via a templated function which uses types interference: auto cleanup_socket = make_scope_guard([&]{ close_socket(s); }); Searching for scope_guard yields lots of alternative implementations.