Я только что натолкнулся на некоторую реализацию контейнера в C ++. Этот класс использует внутренний буфер для управления своими объектами. Это упрощенная версия без проверок безопасности:
template <typename E> class Container
{
public:
Container() : buffer(new E[100]), size(0) {}
~Container() { delete [] buffer; }
void Add() { buffer[size] = E(); size++; }
void Remove() { size--; buffer[size].~E(); }
private:
E* buffer;
int size;
};
AFAIK это будет строить / разрушать E
объекты избыточно в Container()
а также ~Container()
если new
/delete
не настроены. Это кажется опасным.
Использует размещение new
в Add()
лучший способ предотвратить опасные избыточные вызовы конструктора / деструктора (кроме привязки класса к полнофункциональному пулу)?
При использовании размещения new
, было бы new char[sizeof(E)*100]
быть правильным способом для выделения буфера?
AFAIK это будет строить / разрушать
E
объекты избыточно
Казалось бы, так. new
В массиве ed уже применяется конструктор по умолчанию и delete[]
будет вызывать деструктор, а также для всех элементов. По сути, Add()
а также Remove()
методы добавить немного, кроме как поддерживать size
счетчик.
При использовании нового размещения будет
new char[sizeof(E)*100]
быть правильным способом для выделения буфера?
Лучше всего было бы выбрать std::allocator
это уже решает все проблемы с памятью.
Использование места размещения new
а управление памятью самостоятельно требует, чтобы вы знали о ряде проблем (в том числе);
Ничто из этого невозможно преодолеть, это только что было сделано в стандартной библиотеке. Если вы заинтересованы в поиске пользовательского распределителя, функции глобального распределения (void* operator new (std::size_t count);
) будет подходящей отправной точкой для выделения памяти.
Без дальнейших пояснений относительно первоначального назначения кода — std::vector
или std::array
было бы гораздо лучше варианты для управления элементами в контейнере.
Есть ряд проблем с кодом.
Если вы позвоните Remove()
перед звонком Add()
вы будете выполнять назначение в разрушенный объект.
В противном случае delete[] buffer
вызовет деструктор 100 объектов в массиве. Который, возможно, был вызван раньше.
Вот действительная программа:
#include <iostream>
int counter=0;
class Example {
public:
Example():ID(++counter){
std::cout<<"constructing "<<ID<<std::endl;
}
~Example(){
std::cout<<"destructing "<<ID<<std::endl;
ID=-1;
}
private:int ID;
};
template <typename E> class Container
{
public:
Container() : buffer(new char [100*sizeof(E)]), size(0) {}
~Container() {
for(size_t i=0;i<size;++i){
reinterpret_cast<E*>(buffer)[i].~E();
}
delete [] buffer;
}
void Add() { new (buffer+sizeof(E)*size) E(); size++; }
void Remove() { reinterpret_cast<E*>(buffer)[--size].~E(); }
private:
void* buffer;
size_t size;
};int main() {
Container<Example> empty;
Container<Example> single;
Container<Example> more;
single.Add();
more.Add();
more.Remove();
more.Add();
more.Add();
more.Remove();
return 0;
}