Search code examples
c++vectorsizecapacity

"Safe" way to add an element to a std::vector beyond its size() but under its capacity()


It might sound dangerous, but I'm trying to do something like this:

std::vector<StructureSlowToBeCreated> vElems;

StructureSlowToBeCreated s1, s2;

vElems.reserve(many_slots_for_structs);

vElems[x1] = s1; // I can ensure x1, x2 < many_slots_for_structs
vElems[x2] = s2;

Basically, the idea is to avoid using

vElems.resize(many_slots_for_structs);

Since both s1 and s2 are slow to be created, hence I don't want to do it twice. As I said, I can 100% ensure x1 and x2 are going to be within the vector capacity boundaries, but also many times certainly outside the size boundaries (ergo, using "at()" would end up in an exception).

Is there a cleaner way to do this? Or should I consider this one clean enough (I've the feeling it isn't).

And I really need to place s1 at the x1 index, otherwise, I'd need to store x1 as a parameter of s1 and store a secondary map to link x1 with the position of s1 in the vector (and I'd add the cost of looking the map on each access to s1 or s2, something I'd like to avoid at all cost).

Thanks a lot for your help.


Solution

  • You can not access a std::vector above its size. It may seem to work, but it is UB and it will generate problems at the end.

    The normal way to perform this task would be to use a map, so that you only create the elements you need. However, finding the n-th element is O(logn) instead of constant time for the std::vector.

    std::map<size_t, StructureSlowToBeCreated> myMap;
    

    If you really need constant time access, you have to resize the vector. I understand that you do not want to default-construct all the elements because it is a time-consuming operation. Then, you can create an std::vector of other elements that store your object. For example:

    std::vector<std::optional<StrSlowToBeCreated>> myVec; // as suggested by GManNickG
    std::vector<std::unique_ptr<StructureSlowToBeCreated>> myVec;
    

    Probably, you can choose between optional and unique_ptr depending of the object size.