【问题标题】:How does std::vector in c++ gets deallocated by defaultc++ 中的 std::vector 默认如何被释放
【发布时间】:2021-10-15 12:55:51
【问题描述】:

我已经读过,在 C++ 中,一旦变量超出范围,STL 的向量就会被释放。所以我尝试通过STL的向量实现,但它似乎并没有发生在类向量的析构函数中,那么释放是如何发生的或者它是如何实现的。

【问题讨论】:

  • 它发生在 something 的析构函数中。 vector 本身或其数据成员之一或其基类子对象之一,具体取决于实现。
  • 为了异常安全,内存通常由基类管理。请参阅 Stroustrup 的 Exception Safety: Concepts and Techniques 讨论这些问题和一个小的向量示例。
  • 您想检查一下Vector Container 的重新实现吗?

标签: c++ stl


【解决方案1】:

我已经读过,在 C++ 中,一旦变量超出范围,STL 的向量就会被释放。

您的搜索关键字是对象生命周期、变量的范围存储持续时间

这与std::vector 无关。如果控制流离开当前作用域,则生命周期绑定到该作用域(通过自动存储持续时间)的任何对象都会自动销毁。

供参考:


所以我尝试通过STL的向量实现,但它似乎没有发生在类向量的析构函数中,那么释放是如何发生的或者它是如何实现的。

标准库容器管理它们分配的内存和它们通过分配器创建的对象。 (但我认为这些细节对于基本功能的一般理解并不重要。)

供参考:

【讨论】:

    【解决方案2】:

    std::vector 使用 destructor 调用 std::vector::_Tidy (MSVC 实现)销毁(或删除)。当向量超出范围或手动销毁向量时会发生这种情况。

    【讨论】:

      【解决方案3】:

      std::vector 类的确切销毁位置由规范留待实现。

      但通常(当向量超出范围时),它应该导致调用std::allocatordeallocate 方法(这是std::vector 的第二个模板参数)。
      另见What's the advantage of using std::allocator instead of new in C++?

      实际上,请记住,标准类没有成为实际文件的规则(这意味着您可以安全地忽略在那里看到的内容,只要您的代码遵循 C++ 标准,因为这些是编译器的一部分,而不是 C++)。

      【讨论】:

      • std::vector 的内存管理由其分配器处理,即第二个模板参数。默认为std::allocator,不使用malloc/free
      【解决方案4】:

      有几种 STL 实现,它们彼此不同,但它们是相似的。我们以最新版GCC的libstdc++为例:

      std::vector的析构函数,通过调用std::_Destroy销毁vector中的所有元素

            ~vector() _GLIBCXX_NOEXCEPT
            {
          std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,
                    _M_get_Tp_allocator());
          _GLIBCXX_ASAN_ANNOTATE_BEFORE_DEALLOC;
            }
      

      vector 有一个基类:

        template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
          class vector : protected _Vector_base<_Tp, _Alloc>
      

      对于vector本身使用的内存,在基类的_M_deallocate中销毁,最后会调用deallocate

            ~_Vector_base() _GLIBCXX_NOEXCEPT
            {
          _M_deallocate(_M_impl._M_start,
                    _M_impl._M_end_of_storage - _M_impl._M_start);
            }
      
            void
            deallocate(_Tp* __p, size_type __n __attribute__ ((__unused__)))
            {
      #if __cpp_sized_deallocation
      # define _GLIBCXX_SIZED_DEALLOC(p, n) (p), (n) * sizeof(_Tp)
      #else
      # define _GLIBCXX_SIZED_DEALLOC(p, n) (p)
      #endif
      
      #if __cpp_aligned_new
          if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
            {
              _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n),
                           std::align_val_t(alignof(_Tp)));
              return;
            }
      #endif
          _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n));
            }
      

      _GLIBCXX_OPERATOR_DELETE是一个宏,我们可以把它当成delete

      【讨论】:

        【解决方案5】:

        向量的析构函数会破坏向量在其生命周期内创建的动态内存及其内容。

        当向量超出范围时,它的析构函数会作为其自身销毁的一部分自动运行。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-08-30
          • 2023-03-22
          • 1970-01-01
          • 2012-10-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多