I think I got your point. I can pass the total number of affected rows returned by the database query and use that for preallocation. But when my vector faces a case where I can not preallocate exactly because the number of items is not known, the performance will still drop, do you have any tips for that?
Usually you decide based on the specific requirements, limitations and common patterns; and if you don't know the requirements, you give some levers of control to the user of your class/library.
As an example of requirements, it may be that you must have an average insertion time below some time, or your requirement may be that you can't spend more than some time on the insertion (maximum instead of average). Or maybe the time is not as important but you shouldn't waste extra memory. There may be other requirements that could affect the design decisions, like whether other operations on the container should be optimized for, whether objects should never be moved, etc.
A limitation may be that you know how many elements there could be at max (e.g. having more would be a logical error, e.g. more than 6 sides of a cube, more than 7 days in a week). This one sometimes is difficult to balance not to explode your next rocket https://en.m.wikipedia.org/wiki/Ariane_flight_V88
A pattern could be for example, that the elements are often inserted in batches of specific size, or the size of the container usually caps at some size and then the elements are reused. Or there is known the most common amount of elements or their size.
For the exposed levers, std::vector exposes functions like resize, reserve, size, and capacity that allow to move all the decisions about memory allocation to the user side, so if the user of std::vector needs to and knows how to better optimize the allocation strategy, they can do that.