Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

Let\'s say we have an opaque type handle_t that is managed through a simple inte

ID: 658901 • Letter: L

Question

Let's say we have an opaque type handle_t that is managed through a simple interface with functions such as:

handle_t *handle_init(void);
int handle_do(handle_t *);
void handle_free(handle_t *);
The problem is that the size cannot be always determined in the initialization step and it has to be calculated in handle_do. One solution I have seen is calling handle_do two times, the first of which returns the size needed to allocate, but doesn't that affect the performance?

Is it a bad practice to allocate or reallocate memory in handle_do? Does it even matter when using handle types (since the init/free routines are made clear)?

Explanation / Answer

Your question is a little bit unclear. There is no "size" in your code example, I guess you are talking about the size of some internal array of the type "handle_t". I further assume at the time when handle_init is called, it is not clear how often handle_do will be called, or which additional parameters to handle_do will be passed, with different impact on the needed memory.

Actually, from a viewpoint of the user of your API, it should not matter how and where the allocation is done. If "handle_t" is an opaque type, your module should abstract away the internal memory allocation strategy from the user of your module. If and where you alloc, realloc and free any internal data structures should be kept hidden from outside. Under no circumstances the user of the module should have to call handle_do twice by himself (in an "calculate mode" and an "allocate mode") if the only reason for the double call is the memory calculation. That would unintuive and thus error prone.

So what to do internally, inside of your module? This depends. If I got you right, you are thinking about either doing some realloc in handle_do, or alternatively doing some of the memory size calculation steps twice, once just for finding out how much memory you are going to allocate, and once for the actual allocation. Both can be viable strategies, and both have some drawbacks. Lots of reallocations can have a negative impact on performance, but doing some time-intensive calculations twice, too, and the latter can make your code more complicated, so there is always a trade-off.

As a compromise, I suggest you check if you can implement your type along the lines of the following example: the std::vector implementation in C++.

A std::vector has a size and a capacity, where the size is always less or equal the capacity. When a vector operation increases the size beyond the capacity, the capacity is automatically increased (by a multiplicative factor, not just by 1!). This will lead to some internal reallocation, but for most real-world cases not too many reallocations. The user of a vector can also ask for more capacity at the "initializiation", so this can reduce the number of necessary reallocations at later point in time.

So in your case: check if handle_init can do some small allocation beforehand, and if handle_do notices that the preallocated memory is too small, it will automatically reallocate (with some extra margin if you expect further operations which might need even more internal memory).