【问题标题】:Deallocating (and calling a destructor of) a template argument释放模板参数(并调用其析构函数)
【发布时间】:2013-03-24 19:53:00
【问题描述】:

上下文

我正在尝试实现我的std::vector 模板类版本。向量包含模板参数T的动态数组:

_vec = new T[n];

显然T 可以是任何类型,指针、类、原始类型。当对大小为6 的向量调用v.resize(4) 时,它显然应该删除this specification 之后的动态数组的最后两个元素(不重新分配数组):

如果 n 小于当前容器大小,则内容将减少到它的前 n 个元素,删除超出的那些(并销毁它们)。

破坏我的意思是,我认为 std 库的意思是,调用对象的析构函数或简单地释放内存空间,如果它是包括指针在内的任何其他原始类型。

问题:是否可以(如果可以,如何)销毁动态分配的数组中的模板元素而不解除分配和重新分配?

我尝试了什么?好吧,我真的不知道从哪里开始:

  • 显然you shouldn't 在原始类型上调用delete
  • You can 显式调用对象上的析构函数,但如果 T 不是对象,这将不起作用。
  • 我想只是减少​​内部 _size 计数器(以便将来的 push_back 元素将被覆盖),但这不会立即调用对象的析构函数。

【问题讨论】:

    标签: c++ dynamic-allocation


    【解决方案1】:

    new T[n] 不是您想要的,因为这已经创建了T 类型的n objects,但您只想为 up 分配 memoryn 类型为T 的对象。

    您可能需要阅读placement-new 语法和placement-delete 语法。 Wikipedia

    【讨论】:

    • 对于std::vector,我很确定标准规定您在分配器中使用constructdestroy 函数,而不是显式使用placement-new 和explicit-destructor-calls .
    • 你是对的,但如果 Jueecy 这样做只是为了好玩,那么分配器可能是矫枉过正。
    【解决方案2】:

    当您实现vector 时,您可能希望将存储管理和对象管理分开。

    使用allocator::allocate(size_type n)allocator::deallocate(pointer p, size_type n) 管理存储,通常分别以return ::operator new(n * sizeof (T));::operator delete(p); 实现。

    这些函数分配和释放内存,但不为该内存中包含的对象调用构造函数或析构函数。

    使用allocator::construct(U* p, Args&&... args);allocator::destroy(U* p); 管理对象的生命周期,它们通常分别实现为::new((void *)p) U(std::forward<Args>(args)...);p->~U()

    这些函数在预分配的内存中构造和解构对象,但它们本身并不管理内存。

    【讨论】:

      【解决方案3】:

      FredOverflow 关于对象分配是正确的。

      根据您的问题,您只需将对象与非对象(标量)区分开来。在 Visual Studio 2010 发行版中有来自<xmemory> 的真实代码:

      template<class _Alloc> inline void _Destroy_range(
        typename _Alloc::pointer _First, typename _Alloc::pointer _Last, _Alloc& _Al);
      
      template<class _Alloc> inline void _Destroy_range(
        typename _Alloc::pointer _First, typename _Alloc::pointer _Last, _Alloc& _Al, 
        _Nonscalar_ptr_iterator_tag);  // Object overload
      
      template<class _Alloc> inline void _Destroy_range(
        typename _Alloc::pointer _First, typename _Alloc::pointer _Last, _Alloc& _Al, 
        _Scalar_ptr_iterator_tag);  // Non-object overload
      

      他们使用带有特殊标志的简单调度,可以使用某些特征类计算。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-26
        • 2018-02-03
        • 2012-10-06
        • 2020-02-15
        • 2013-02-16
        • 2020-07-21
        相关资源
        最近更新 更多