Использование размещения нового в контейнере

Я только что натолкнулся на некоторую реализацию контейнера в 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] быть правильным способом для выделения буфера?

1

Решение

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 было бы гораздо лучше варианты для управления элементами в контейнере.

3

Другие решения

Есть ряд проблем с кодом.
Если вы позвоните 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;
}
1

По вопросам рекламы [email protected]