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).
handle_init
,handle_do
andhandle_free
, you almost certainly want an object withinit
handled in the ctor,free
handled in the dtor, anddo
handled in a member function--possibly but not necessarily anoperator()
. Allocation probably should be internal to the object, likely via astd::unique_ptr
or some other smart pointer type.