Live data from Hacker News

Stupid Smart Pointers in C

blog.kevinalbs.com

141–150 of 174 posts

Re: Stupid Smart Pointers in C

#141

Earlier quoted context omitted.

Of course the libc allocator is slow, it's designed as a one-size-fits-all solution that's poorly tuned for most workloads and often doesn't get substantially updated for decades. By writing your own, you aren't avoiding an allocator, you're just avoiding the libc implementation of an allocator. (In fact, most libcs let you just redefine the malloc(), free(), and realloc() functions to point to your own allocator ins…

I guess I'm confused at this chain of responses, then. As I'm doing what you are already suggesting. Re-reading your comment, about the "not really freeing anything" -- I beg to differ, as when you do a real free(), it frees up memory for any program to use. As I already mentioned one of the benefits is once you have control of who can use that memory and aren't risking it not being available - disregarding some prog…

when you do a real free(), it frees up memory for any program to use

This is an extremely naive description of not only what the libc free() function does, but also of how memory management works in general.

Re: Stupid Smart Pointers in C

#142
post #5

Really, don't do this, it's a portability and safety nightmare (aside from C not being memory safe already). C programmers are better off with either of these two techniques: * Use __attribute__((cleanup)). It's available in GCC and Clang, and we hope will be added to the C spec one day. This is widely used by open source software, eg. in systemd. * Use a pool allocator like Samba's talloc ( https://talloc.samba.org/…

> Use __attribute__((cleanup)). It's available in GCC and Clang Really, don’t do this, it’s a portability nightmare. If you’re going to write C stick to code that easy to run under MSVC.

Running under MSVC is overrated and more trouble than its worth. Clang and mingw-w64 GCC work just fine for targeting Windows.

Re: Stupid Smart Pointers in C

#143
post #140
post #5

Really, don't do this, it's a portability and safety nightmare (aside from C not being memory safe already). C programmers are better off with either of these two techniques: * Use __attribute__((cleanup)). It's available in GCC and Clang, and we hope will be added to the C spec one day. This is widely used by open source software, eg. in systemd. * Use a pool allocator like Samba's talloc ( https://talloc.samba.org/…

> ... plus [reference counting] interacts badly with how modern CPUs work. Can you expand on this?

I'm not sure what the reference to "modern CPUs" is, but a common complaint is that most reasonable reference counting implementations suffer very badly under contention. Specifically, if an object's reference count is contended (an object is being accessed/its pointer copied by many threads), it's possible that incrementing and then decrementing the reference count can take several hundred cycles due to either cache lines ping-ponging between cores or relatively expensive remote atomics (some Arm CPUs, I believe, allow the memory system to execute atomic operations in caches themselves to try and cope with contention/avoid moving cache lines back and forth by simply leaving them in a shared cache).

In reality, your milage will heavily vary. If you don't have contention (you don't commonly share objects across multiple threads concurrently), it's likely that reference counting will perform very well. Whether this is the common case really depends on the kinds of software you write.

Re: Stupid Smart Pointers in C

#144

Earlier quoted context omitted.

I guess I'm confused at this chain of responses, then. As I'm doing what you are already suggesting. Re-reading your comment, about the "not really freeing anything" -- I beg to differ, as when you do a real free(), it frees up memory for any program to use. As I already mentioned one of the benefits is once you have control of who can use that memory and aren't risking it not being available - disregarding some prog…

when you do a real free(), it frees up memory for any program to use This is an extremely naive description of not only what the libc free() function does, but also of how memory management works in general.

[deleted]

Re: Stupid Smart Pointers in C

#145

Earlier quoted context omitted.

might as well free the NULL pointers as well - this is totally valid C and can simplify the code

I suppose the implication is that, checking for null allows your cleanup logic to be more complex than simply calling free() for example, the object could be managing an open file, or an open socket

simply checking for NULL doesn't allow that - for example for something that might have been opened with fopen() needs to be closed with fclose() rather than free(), and you can't tell that from the pointer.

Re: Stupid Smart Pointers in C

#146

Earlier quoted context omitted.

Of course the libc allocator is slow, it's designed as a one-size-fits-all solution that's poorly tuned for most workloads and often doesn't get substantially updated for decades. By writing your own, you aren't avoiding an allocator, you're just avoiding the libc implementation of an allocator. (In fact, most libcs let you just redefine the malloc(), free(), and realloc() functions to point to your own allocator ins…

I guess I'm confused at this chain of responses, then. As I'm doing what you are already suggesting. Re-reading your comment, about the "not really freeing anything" -- I beg to differ, as when you do a real free(), it frees up memory for any program to use. As I already mentioned one of the benefits is once you have control of who can use that memory and aren't risking it not being available - disregarding some prog…

> you have control of who can use that memory and aren't risking it not being available

overcommit would like to have a word

Re: Stupid Smart Pointers in C

#147

IMHO trying to emulate smart pointers in C is fixing a problem that shouldn't exist in the first place, and is also a problem in C++ code that uses smart pointers for memory management of individual objects. Objects often come in batches of the same type and similar maximum lifetime, so let's make use of that. Instead of tracking the individual lifetimes of thousands of objects it is often possible to group thousands…

This is the way

It makes the code so much simpler. And quite probably faster as there's less malloc/free churn.

A lot of problems break down to:

* we need this effectively forever (i.e. until config reload)

* we need this very briefly when processing a task or request

Sometimes you need a cache that has intermediate lifetimes, but that is a much smaller problem to deal with, and you can often cope with manual memory management for that

Hook any file handles and other resource cleanup functions into the same pools and you have a pretty easy life.

Re: Stupid Smart Pointers in C

#148

Or rather, given that every relevant C compiler is also a c++ compiler, just compile as c++ and use std::unique_ptr? I love C but I just can't understand the mental gymnastics of people that prefer this kind of hacks compared to just using C++

There's a lot of either "I like to pretend C is simple and simple is good" or "C++ has things I don't like, so I will refuse to also use the things I do like out of spite". You see it all over the place here whenever C or C++ comes up.

Using C++ while keeping people on a common subset of C++ features is very hard in practice. Google for example do a pretty extreme amount of restrictive code standard, training, linting and reinventing libraries to that end.

A lot of the motivation behind inventing golang seems to be to remove C++ toys, because it's too hard to get people to not use them if they're there.

Re: Stupid Smart Pointers in C

#149
post #140

Earlier quoted context omitted.

> ... plus [reference counting] interacts badly with how modern CPUs work. Can you expand on this?

I'm not sure what the reference to "modern CPUs" is, but a common complaint is that most reasonable reference counting implementations suffer very badly under contention. Specifically, if an object's reference count is contended (an object is being accessed/its pointer copied by many threads), it's possible that incrementing and then decrementing the reference count can take several hundred cycles due to either cache…

Same object doesn't have to be contended if the reference count is sharing cache line with another reference count.

I've seen this happen in cases arrays of objects are allocated, ie one per thread, and then handed to a thread pool to work on.

Even if heap allocated, if the object is just a reference counter and a few pointers, the memory allocator can fit several of them next to each other causing them to share cache lines, which causes the performance issues with atomic operations.

Depends on implementation of things of course, but can be a pitfall.

Re: Stupid Smart Pointers in C

#150

[flagged]

We have 50 years of experience of code telling us that, no, programmers are not consistently capable of avoiding memory safety just by being good about it. Saying that it's just a failing of lesser programmers is the height of extreme arrogance, since I guarantee you that you've written memory safety vulnerabilities if you've written any significant amount of C code. The problem is not that the rules are hard to foll…

The solution to that is to either:

1) If you're gonna return pointers, don't use an allocation scheme that invalidates pointers in the implementation of map_t.

2) If you want to reallocate and move memory, don't return pointers, return abstracted handles/indices.

Both of those are completely possible and not particularly unergonomic to do in C. If you need to enforce invariants, then enforce them, C does have enough abstraction level for that.

Post reply on HN