4 ms·
Callback based APIs are better, but not good enough. The problem remains that the user still has to deal with some potentially undesirable constraints: * I may
by 10000truths 3y ago
Callback based APIs are better, but not good enough. The problem remains that the user still has to deal with some potentially undesirable constraints:
* I may be running in an environment where allocating memory is an asynchronous operation. A callback based API forces me to block, which can cause unpleasant side effects like halting an event loop.
* In my experience, some libraries with custom allocation hooks forget to define one or both of the two basics in the callback signature: a "context" or "user data" parameter, and a way to return an error.
The proper solution is to decouple memory allocation from object initialization entirely. There are two different approaches to this:
1. Expose get_foo_size() and get_foo_align() functions that return the size and alignment that the opaque foo struct needs (at runtime, of course). Then I as the user can allocate that memory, and initialize my opaque foo objects in-place:
size_t foo_size = get_foo_size();
void* buf = alloc_aligned_memory(foo_size * 1000, get_foo_align());
for(size_t i = 0; i < 1000; ++i) {
int err = foo_init(buf + i * foo_size, /* params here */);
}
2. Define foo_init(void* buf, size_t len, ...) which attempts to initialize an opaque foo object in the buffer defined by [buf, buf+len). If the buffer does not have enough space, return an error. Otherwise, return the number of bytes actually used by the object.
- chongli 3y agoThat second method works fine if you just want a buffer of a bunch of foo’s and they all happen to be the same size. Not so fine if foo is a data structure in its own right with growable capacity.