如何在动态数组中的某些对象上调用析构函数

时间:2019-06-12 01:06:01

标签: c++ templates placement-new

我终于开始尝试新的放置方式以创建有效的动态数组。目的是了解其工作原理,而不是替换类向量。构造函数起作用。分配了一个块但未初始化。添加每个元素后,将对其进行初始化。但是我看不到如何使用放置删除仅在那些存在的元素上调用析构函数。谁能解释一个?该代码用于随着数组的增长一个接一个地分配元素,但是删除不正确。

template<typename T>
class DynArray {
private:
  uint32_t capacity;
  uint32_t size;
  T* data;
  void* operator new(size_t sz, T* place) {
    return place;
  }
  void operator delete(void* p, DynArray* place) {
  }

public:
  DynArray(uint32_t capacity) :
     capacity(capacity), size(0), data((T*)new char[capacity*sizeof(T)]) {}
  void add(const T& v) {
        new(data+size++) T(v);
  }
  ~DynArray() {
     for (int i = 0; i < size; i++)
       delete (this) &data[i];
     delete [] (char*)data;
  }
};

2 个答案:

答案 0 :(得分:1)

您实际上发现了唯一一种(至少我知道)要手动调用析构函数的情况:

  ~DynArray() {
     for (int i = 0; i < size; i++)
       data[i].~T();
     delete [] (char*)data;
  }

结合一个简单的类和main,您应该获得预期的结果:

struct S {
    ~S() { std::cout << __PRETTY_FUNCTION__ << '\n'; }
};

int main() {
    DynArray<S> da{10};
    da.add(S{});
    return 0;
}

请注意,自DynArray通过const引用获取对象以来,析构函数被调用了两次,因此它具有临时性。

$./a.out 
S::~S()
S::~S()

答案 1 :(得分:1)

放置delete并没有多大意义,因为析构函数已经完成了放置delete应该做的事情。

普通的delete调用析构函数,然后释放使用new为对象分配的内存。但是,与普通new不同,布局new不会分配内存,只会对其进行初始化。因此,放置delete仅需调用要“删除”的对象的析构函数。

您需要做的就是直接调用数组每个对象的析构函数:

~DynArray() {
   for (int i = 0; i < size; i++)
      data[i].~T();
}

自C ++ 17起,您还可以使用函数模板std::destroy代替直接调用析构函数:

~DynArray() {
   auto first = std::addressof(data[0]);
   auto last  = std::next(first, size);
   std::destroy(first, last);
}