как вызвать деструктор для некоторых объектов в динамическом массиве - PullRequest
3 голосов
/ 12 июня 2019

Наконец-то я нашел способ создать новый эффективный динамический массив. Цель состоит в том, чтобы понять, как это работает, а не заменить вектор класса. Конструктор работает. Блок выделен, но не инициализирован. По мере добавления каждого элемента он инициализируется. Но я не понимаю, как использовать удаление размещения, чтобы вызывать деструктор только для тех элементов, которые существуют. Кто-нибудь может объяснить это? Этот код работает для распределения элементов один за другим по мере роста массива, но удаление не является правильным.

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 ]

1 голос
/ 12 июня 2019

Размещение 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);
}
1 голос
/ 12 июня 2019

Вы действительно нашли единственный случай (по крайней мере, о котором я знаю), когда вы хотите вызвать деструктор вручную:

  ~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()
...