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;
emplace_back():This function can directly insert the object without calling the copy constructor.
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.
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.
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.
There are two things that have escaped your notice:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With