Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is emplace_back calling destructor?

I have a class with deleted copy ctor and a destructor that frees a C resource.

I would expect emplace_back to move objects and call destructor only once, but it's being called in emplace_back, as seen in the stl implementation on linux below. Why is this happening?

The result is that the C resource is being freed more than once.

    statement(statement&&) = default;                                                 
    statement& operator=(statement&&) = default;                                      

   private:                                                                           
    statement(const statement&) = delete;                                             
    statement& operator=(const statement&) = delete;




396│   template<typename _Tp, typename _Alloc>
397│     template<typename... _Args>
398│       void
399│       vector<_Tp, _Alloc>::
400│       _M_emplace_back_aux(_Args&&... __args)
401│       {
402│         const size_type __len =
403│           _M_check_len(size_type(1), "vector::_M_emplace_back_aux");
404│         pointer __new_start(this->_M_allocate(__len));
405│         pointer __new_finish(__new_start);
406│         __try
407│           {
408│             _Alloc_traits::construct(this->_M_impl, __new_start + size(),
409│                                      std::forward<_Args>(__args)...);
410│             __new_finish = 0;
411│
412│             __new_finish
413│               = std::__uninitialized_move_if_noexcept_a
414│               (this->_M_impl._M_start, this->_M_impl._M_finish,
415│                __new_start, _M_get_Tp_allocator());
416│
417│             ++__new_finish;
418│           }
419│         __catch(...)
420│           {
421│             if (!__new_finish)
422│               _Alloc_traits::destroy(this->_M_impl, __new_start + size());
423│             else
424│               std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator());
425│             _M_deallocate(__new_start, __len);
426│             __throw_exception_again;
427│           }
428├>        std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
429│                       _M_get_Tp_allocator());
430│         _M_deallocate(this->_M_impl._M_start,
431│                       this->_M_impl._M_end_of_storage
432│                       - this->_M_impl._M_start);
433│         this->_M_impl._M_start = __new_start;
434│         this->_M_impl._M_finish = __new_finish;
like image 883
piotr Avatar asked Feb 08 '14 13:02

piotr


People also ask

Does Emplace_back call constructor?

emplace_back():This function can directly insert the object without calling the copy constructor.

Is Emplace_back better than Push_back?

With the simple benchmark here, we notice that emplace_back is 7.62% faster than push_back when we insert 1,000,000 object (MyClass) into an vector. Insert 1,000,000 objects. --- push_back --- push_back takes 0.00665344 seconds.

What is the function of Emplace_back?

The C++ function std::vector::emplace_back() inserts new element at the end of vector. Reallocation happens if there is need of more space. This method increases container size by one.

When should I use Emplace_back?

Specific use case for emplace_back : If you need to create a temporary object which will then be pushed into a container, use emplace_back instead of push_back . It will create the object in-place within the container.


1 Answers

There are two things that have escaped your notice:

  1. A moved-from object will still be destructed, so your move operation must transfer resources
  2. When a vector grows, it might need to re-allocate which is a 4 steps operations: acquire new storage, move-construct (or copy-construct) new elements in the new storage (from the old), destroy old elements, release old storage.

So, your problem is simply that you do not transfer resources properly; using std::unique_ptr as the basis of your custom class and you will not suffer such woes.

like image 163
Matthieu M. Avatar answered Oct 19 '22 05:10

Matthieu M.