Live data from Hacker News

Memory management in C programs (2014)

nethack4.org

81–90 of 106 posts

Re: Memory management in C programs (2014)

#81

Earlier quoted context omitted.

> plenty of modern code written in languages like C++ (whose exception support is often eschewed) and Go gets by without [exceptions]. I would not consider C++ code that eschews exceptions "modern". To eschew exceptions almost always entails giving up RAII, and if you give up RAII you've done yourself a huge disservice: you're now stuck manually managing memory and resources, and suffering all the bugs that come with…

RAII (or rather the only useful part of the idea: that the destructor is called when an object goes out of scope) without exceptions is totally fine if you're not too dogmatic about initialising everything (especially not things that can go wrong) in the constructor but instead have one or more separate init methods with a return value. The only important part is to cleanup everything in the destructor. This is all I…

Being able to construct without initialising is the flipside of being able to descope without deinitialising, and introduces much the same problems. It makes it much harder to use immutability (admittedly something that's hard in C++ in any case). It makes sharing objects between threads much harder to reason about, as you need to make sure init a) only happens once, but more importantly b) the effects are visible to any other thread before it uses the object.

How much code have you written with exceptions? A lot of features you don't miss if you don't use them, but once you're used to use them it's very frustrating to live without them. Back when I wrote C I never thought "gee it would be nice to use an anonymous function here", but now that I'm used to them it's very frustrating to not have them.

Re: Memory management in C programs (2014)

#82
post #42

Earlier quoted context omitted.

Constructors are resource allocation, so they can always fail.

You can't really tell if the stack overflowed in a constructor though, plus that will essentially /never/ happen, so I think it's okay to exclude stack overflows when creating stack allocated objects as failure conditions. In that case no, a lot of constructors won't be able to fail.

new can and does fail when you're out of memory, and this is a condition that many programs do need to handle (for some programs crashing is appropriate and in that case sure, you can live without exceptions). In a pedantic technical sense that's not the constructor failing, but your options for handling it are much the same.

Re: Memory management in C programs (2014)

#83
post #37

Earlier quoted context omitted.

As a non-C user, C was always too forboding. I wrote a bit of it, and read K&R, but places like HN bang into your head that you'll likely make a horrible screw-up writing C, your code won't be secure, and it's better not to bother. Maybe I should spend some more time with it.

You might enjoy trying some embedded development. Memory management and object lifetimes are usually less complex, and security is not an issue unless the device talks to the internet. You rarely feel like you are "fighting" C; it feels like the right tool for the job.

Well, that's because it IS the right tool for the job. C was built for systems programming: kernels, filesystems, and the like. It really wasn't built for applications space programming.

Re: Memory management in C programs (2014)

#84
post #75
post #62

Earlier quoted context omitted.

>> C++ is hard enough to get right without exceptions > In what manner? I guess he's referring to noexcept/basic/strong exception guarantees. Yes, writing code with strong guarantees is hard, but what makes it hard is that you have to write your code "transactionally", i.e., either 1) prepare changes and "commit" them in one go, or 2) roll back changes if an exception occurs. But writing code with "strong guarantee"…

Its not harder. You know exactly where that function can return, with exceptions its very hard to know what might throw in practice.

With exceptions you can use something like scoped exit (http://www.boost.org/doc/libs/1_61_0/libs/scope_exit/doc/htm...) for automatic rollback and neat cleanup even in multilevel "transactions". With error codes, nothing happens automatically, hence it's easy to mess up cleanup/rollback.

Yes, you can still use RAII for rollback/cleanup in combination with error codes, but then you get the worst of both worlds: the (minor) complication of writing RAII classes AND code cluttered with manual error-checking.

Re: Memory management in C programs (2014)

#85
post #81

Earlier quoted context omitted.

RAII (or rather the only useful part of the idea: that the destructor is called when an object goes out of scope) without exceptions is totally fine if you're not too dogmatic about initialising everything (especially not things that can go wrong) in the constructor but instead have one or more separate init methods with a return value. The only important part is to cleanup everything in the destructor. This is all I…

Being able to construct without initialising is the flipside of being able to descope without deinitialising, and introduces much the same problems. It makes it much harder to use immutability (admittedly something that's hard in C++ in any case). It makes sharing objects between threads much harder to reason about, as you need to make sure init a) only happens once, but more importantly b) the effects are visible to…

You can perfectly well have classes which have different levels of initialization and clean them all up in the destructor...

RAII is generally useful without exceptions.

Re: Memory management in C programs (2014)

#86
post #81

Earlier quoted context omitted.

RAII (or rather the only useful part of the idea: that the destructor is called when an object goes out of scope) without exceptions is totally fine if you're not too dogmatic about initialising everything (especially not things that can go wrong) in the constructor but instead have one or more separate init methods with a return value. The only important part is to cleanup everything in the destructor. This is all I…

Being able to construct without initialising is the flipside of being able to descope without deinitialising, and introduces much the same problems. It makes it much harder to use immutability (admittedly something that's hard in C++ in any case). It makes sharing objects between threads much harder to reason about, as you need to make sure init a) only happens once, but more importantly b) the effects are visible to…

Admittedly I haven't written much code with exceptions, only when using C++ frameworks that heavily rely on them, but this was always for tools where productivity was more important than performance, my actual background is game development.

I have stumbled more recently over another case where the constructor/destructor paradigm in C++ is not ideal, since in some cases it 'encourages' constructing objects on the heap, just for the reason that allocation and initialisation are the same operation, I haven't thought this completely through yet, but bear with me:

Basically I'm trying to write code in a way that minimizes heap allocations. In the extreme case I have just one big 'application object', and all other objects are embedded in this application object. For variable number of objects, pools/arrays with the max capacity are embedded. If taken to the extreme, this model only does a single allocation at application startup (or it could even live on the stack).

However, there are systems which need to be initialized later, and in a specific order (for instance rendering, audio, input, etc...). The objects for these systems have already been created and had their constructor run, but they are not ready for use. That's where I need separate initialisation steps, unless I want to put those objects back on the heap. And in reverse, I need to teardown graphics, audio, input before the big application object is destroyed (and the destructors of the embedded objects are called).

Now I don't think that this extreme case of trying to minimize dynamic allocations down to 1 is particularly useful in real world code, it's more of a though experiment, but in this case, the good ol'e C way of separating allocation/deallocation from initialization/teardown is actually more useful.

Unfortunately I have stumbled over C++ frameworks which basically require to create all objects on the heap, which in my opinion is a design fault. A framework should not dictate to its users whether objects are created on the stack, on the heap, or are embedded in other objects.

Re: Memory management in C programs (2014)

#87

Earlier quoted context omitted.

It depends on what kind of programs you like to write. Personally I like to write things like programming languages or VT100-based text editors. And I like the added challenges that C presents, especially related to data modeling, memory management, lack of first-class functions, etc. So C is a natural choice for me, whereas JS adds little to no value, and actually takes away the challenge.

I hate installing things. :x I get pretty turned on by offering up something like Google Sheets as a webapp that installs and is usable in seconds over the Internet. I used to really love Lua but even though it was

Sure, unless you're the guy who writes Minecraft. People installed that. And Atom. And Spotify. There's still some room for desktop apps like these, granted not as much as before.

Re: Memory management in C programs (2014)

#88
post #37

Earlier quoted context omitted.

You might enjoy trying some embedded development. Memory management and object lifetimes are usually less complex, and security is not an issue unless the device talks to the internet. You rarely feel like you are "fighting" C; it feels like the right tool for the job.

Well, that's because it IS the right tool for the job. C was built for systems programming: kernels, filesystems, and the like. It really wasn't built for applications space programming.

No, C wasn't built for those things. Rather, it just so happens to be suitable for them. C was built as a higher-level alternative to assembly, for writing any kind of computer programs.

Re: Memory management in C programs (2014)

#89
Happened to go look up the Nethack.org page, and hey, the author just "ascended" to the DevTeam earlier this month:

http://www.nethack.org/#News

"""

The DevTeam would like to welcome its latest members. Both of these folks should be familiar to the members of the NetHack community:

Alex Smith, who created the AceHack and NetHack 4 variants. Alex is an expert on the inner workings of the game and the ways in which they can be exploited.

Patric Mueller, who is probably best known as the creator of the UnNetHack variant. Patric also created NetHack-De (German translation of NetHack) and has considerable involvement in the Junethack tournament. Before contracting the dreaded coding bug, Patric was a long time player, having started out on NetHack 3.0 on the Amiga back in the late 80s.

Alex has indicated that, at least initially, he'd be concentrating on improved interface, improved internals, and new features in areas that don't affect the game's gameplay, drawing on some of the features introduced in AceHack and NetHack 4.

Patric's initial focus will be to identify and incorporate changes from a variety of variants into NetHack, in order to expand the gameplay while keeping NetHack's spirit and appeal intact.

Please join us in welcoming Patric and Alex to the DevTeam as we start plans for the next major release.

For the DevTeam, Mike Stephenson

"""

Re: Memory management in C programs (2014)

#90
post #30

if you remember NASAs rules for programming, and MISRAs rules, then dynamic allocation is out of the question. Certainly for most all embedded devices I've worked on all significant memory is statically allocated, and the rest are stack variables. Ideally with proofs of maximum stack depth.

This page is about an old game, though.
Post reply on HN