【问题标题】:Why is emplace_back calling destructor?为什么 emplace_back 调用析构函数?
【发布时间】:2014-03-05 23:04:20
【问题描述】:

我有一个带有已删除复制 ctor 的类和一个释放 C 资源的析构函数。

我希望 emplace_back 移动对象并只调用一次析构函数,但它在 emplace_back 中被调用,如下面的 linux 上的 stl 实现所示。为什么会这样?

结果是 C 资源被多次释放。

    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;

【问题讨论】:

  • 这个答案和我的问题有关:stackoverflow.com/a/12739939/72784
  • 如果您在移动 ctor 上添加一些 noexcept 会怎样?这会有帮助吗?
  • 这看起来像vector 的调整大小函数,即它分配一个新缓冲区,将元素从旧缓冲区复制/移动到新缓冲区,并销毁旧缓冲区中的元素(但不在新缓冲区中)。确保您的移动构造函数正确地转移资源并将被移动的对象留下新资源或不带任何资源,这样它就可以在不影响移动到的对象的情况下被销毁.
  • @detunized vector 仅当移动 ctor 不是 noexcept 并且 可以使用复制 ctor(如果类型为 CopyInsertable)时才会复制。对于statement 类型,复制ctor 是私有的,因此将使用移动ctor(具有较弱的异常安全保证)。
  • @detunized 移动 ctor 是默认值,这意味着它是 noexcept。此外,通过 STL 的代码路径表明正在移动对象。移动 ctor 已删除。

标签: c++ c++11 vector move-semantics


【解决方案1】:

有两件事没有引起您的注意:

  1. 移出的对象仍将被破坏,因此您的移动操作必须转移资源
  2. vector 增长时,它可能需要重新分配,这是一个 4 步操作:获取新存储,移动构造(或复制构造)新存储中的新元素(从旧的),销毁旧元素,释放旧存储。

所以,您的问题只是您没有正确转移资源;使用std::unique_ptr 作为您的自定义类的基础,您将不会遭受这样的困扰。

【讨论】:

  • 我通过显式传输移动构造函数上的资源来修复它,因此在这种情况下析构函数不会释放它。
猜你喜欢
  • 1970-01-01
  • 2020-10-03
  • 2021-08-04
  • 2018-05-24
  • 2015-08-21
  • 1970-01-01
  • 2021-04-01
  • 1970-01-01
相关资源
最近更新 更多