Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resources management - vector and pointers

I need to store a sequence of elements of type ThirdPartyElm, and I'm using a std::vector (or a std::array if I need a fixed size sequence).

I'm wondering how I should initialise the sequence. The first version creates a new element and (if I'm right) creates a copy of the element when it is inserted in the sequence:

for (int i = 0; i < N; i++)
{
   auto elm = ThirdPartyElm();
   // init elm..
   my_vector.push_back(elm);  // my_array[i] = elm;
}

The second version stores a sequence of pointers (or better smart pointers with c++11):

for (int i = 0; i < N; i++)
{
   std::unique_ptr<ThirdPartyElm> elm(new ThirdPartyElm());
   // init elm..
   my_vector.push_back(std::move(elm));  // my_array[i] = std::move(elm);
}

Which is the most lightweight version?

Please highlight any errors.

like image 555
Nick Avatar asked Jan 09 '23 07:01

Nick


2 Answers

You can just declare it with the size, and it will call the default constructor on those elements.

std::vector<ThirdPartyElem> my_vector(N);

As far as your statement

The first version creates a new element and (if I'm right) creates a copy of the element when it is inserted in the sequence

Don't worry about that. Since ele is a local variable that is about to fall out of scope, your compiler will likely use copy elision such that a move will be invoked instead of a copy.

I was mistaken about the above, please disregard that.

like image 56
Cory Kramer Avatar answered Jan 20 '23 18:01

Cory Kramer


Avoid dynamic allocation whenever you can. Thus, generally prefer saving the elements themselves instead of smart-pointers to them in the vector.

That said, either is fine, and if ThirdPartyElem is polymorphic, you wouldn't have a choice.

Other considerations are the cost and possibility of moving and copying the type, though generally don't worry.

There are two refinements to option one which might be worthwhile though:

  1. std::move the new element to its place, as that is probably less expensive than copying (which might not even be possible).
    If the type is only copyable and not movable (legacy, ask for update), that falls back to copying.

  2. Try to construct it in-place, to eliminate copy or move, and needless destruction.

for (int i = 0; i < N; i++)
{
   my_vector.emplace_back();
   try {
       auto&& elm = my_vector.back();
       // init elm..
   } catch(...) {
       my_vector.pop_back();
       throw;
   }
}

If the initialization cannot throw, the compiler will remove the exception-handling (or you can just omit it).

like image 25
Deduplicator Avatar answered Jan 20 '23 19:01

Deduplicator