←back to thread

78 points p2detar | 6 comments | | HN request time: 0.194s | source | bottom
1. writebetterc ◴[] No.46204613[source]
void* is basically used for ad-hoc polymorphism in C, and it is a vital part of C programming.

    void new_thread(void (*run)(void*), void* context);
^- This let's us pass arbitrary starting data to a new thread.

I don't know whether this counts as "very few use cases".

The Memory Ownership advice is maybe good, but why are you allocating in the copy routine if the caller is responsible for freeing it, anyway? This dependency on the global allocator creates an unnecessarily inflexible program design. I also don't get how the caller is supposed to know how to free the memory. What if the data structure is more complex, such as a binary tree?

It's preferable to have the caller allocate the memory.

    void insert(BinTree *tree, int key, BinTreeNode *node);
^- this is preferable to the variant where it takes the value as the third parameter. Of course, an intrusive variant is probably the best.

If you need to allocate for your own needs, then allow the user to pass in an allocator pointer (I guessed on function pointer syntax):

    struct allocator { void* (*new)(size_t size, size_t alignment); void (*free)(void* p, size_t size); void* context; }.*
replies(2): >>46205252 #>>46211624 #
2. warmwaffles ◴[] No.46205252[source]
Curious about the allocator, why pass a size when freeing?
replies(2): >>46205515 #>>46205897 #
3. ◴[] No.46205515[source]
4. naasking ◴[] No.46205897[source]
If you don't pass the size, the allocation subsystem has to track the size somehow, typically by either storing the size in a header or partitioning space into fixed-size buckets and doing address arithmetic. This makes the runtime more complex, and often requires more runtime storage space.

If your API instead accepts a size parameter, you can ignore it and still use these approaches, but it also opens up other possibilities that require less complexity and runtime space by relying on the client to provide this information.

replies(1): >>46209998 #
5. warmwaffles ◴[] No.46209998{3}[source]
The way I've implemented it now was indeed to track the size in a small header above the allocation, but this was only present in debug mode. I only deal with simple allocators like a linear, pool, and normal heap allocator. I haven't found the need for something super complex yet.
6. mrkeen ◴[] No.46211624[source]
void* is a problem because the caller and callee need to coordinate across the encapsulation boundary, thus breaking it. (Internally it would be fine to use - the author could carefully check that qsort casts to the right type inside the .c file)

> What if the data structure is more complex, such as a binary tree?

I think that's what the author was going with by exposing opaque structs with _new() and _free() methods.

But yeah, his good and bad versions of strclone look more or less the same to me.