-2

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.

  • 1
    I think there are plenty of examples and references on how to use vectors out there. And yes, there's a cleaner way, because your way is a bug. – juanchopanza May 04 '17 at 20:57
  • 1
    What about using `reserve` and `push_back` or `emplace_back`? – Galik May 04 '17 at 20:58
  • Either use `emplace_back` so you avoid pointless construction, fix your class so it's not so slow to construct, or use a `std::vector>` (or `boost::optional`) to lazily construct the actual elements. – GManNickG May 04 '17 at 20:59
  • Or use a map, or similar container. –  May 04 '17 at 21:01
  • @NeilButterworth: Good point, I missed the bit about how these need to be at specific indices. Sounds like "hey my container doesn't support this" is probably a good indicator you're using the wrong one. – GManNickG May 04 '17 at 21:04
  • I don't understand the problem. A cleaner way to do... _what_? What is the problem exactly with simply adding these objects to your vector? With an up-front `reserve`, they won't ever need to be copied or moved elsewhere. – Lightness Races in Orbit May 04 '17 at 21:44

1 Answers1

2

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.

J. Calleja
  • 4,855
  • 2
  • 33
  • 54
  • Thanks, the idea of using the std::optional looks elegant and neat. – Alvaro Palma Aste May 05 '17 at 13:19
  • Yes, it is. The problem with optional is that you need either C++17 or boost. Also, the size of an optional is greater than the size of the object it contains. Using unique_ptr is a bit more complicated, but you only need C++11 and the size of unique_ptr is only the size of a pointer. – J. Calleja May 05 '17 at 18:07