2013-04-03 2 views
1

КонтекстDeallocating (и вызов деструктора) шаблон аргумент

Я пытаюсь реализовать свою версию класса std::vector шаблона. Вектор содержит динамический массив шаблона аргумента T:

_vec = new T[n]; 

Очевидно T может быть любого типа, вообще, указатели, классы, примитивные типы. Когда один называть v.resize(4) по вектору размера 6 он должен, очевидно, удалить последние 2 элементов динамического массива (без перераспределении массива) после this specification:

Если п меньше, чем текущий размер контейнера, содержимое сводятся к своим первым n элементам, удаляя их (и уничтожая их).

По разрушив я имею в виду, и я думаю, что средства библиотеки СТД, вызывая деструктор для объекта или просто deallocating пространство памяти, если это любой другой примитивный тип, включая указатели.

Вопрос: Возможно ли (и если да, как) уничтожить элементы шаблона в динамически распределенном массиве без освобождения и перераспределения его?

Что я пробовал? Ну, я искренне не знаю, с чего начать:

  • По-видимому you shouldn't вызов delete на примитивных типов.
  • You can явно вызывает деструктор на объекте, но это не сработает, если T не является объектом.
  • Я думал о простом уменьшении внутреннего счетчика _size (так что в будущем push_back элементы будут перезаписаны), но это не сразу вызовет деструктор для объекта.

ответ

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() соответственно.

Эти функции строят и деконструируют объекты в предварительно распределенной памяти, но сами не управляют памятью.

1

new T[n] не то, что вы хотите, потому что это будет уже создавать nобъектов типа T, но вы только хотите, чтобы выделить памяти до n объектов типа T.

Возможно, вы захотите ознакомиться с синтаксисом синтаксиса размещения и места размещения-размещения. Wikipedia

+0

Для 'std :: vector', я уверен, что стандарт диктует, что вы используете функции' construct' и 'destroy' в распределителе, а не явно используете вызовы place-new и explicit-destructor-calls. – Mankarse

+1

Вы правы, но если Jueecy делает это просто для удовольствия, распределители, вероятно, переборщит. – fredoverflow

0

FredOverflow прав о размещении объекта.

По вашему вопросу все, что вам нужно сделать, это просто отличить объекты от не-объектов (скаляров). Существует реальный код из <xmemory> в визуальной дистрибуции студии 2010:

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 

Они используют простую диспетчеризацию со специальным флагом, который можно вычислить, используя некоторые черты класса.