среда, 25 апреля 2012 г.

C++: Сколько памяти выделяет new []? или несколько слов о placement new

Компилятор позволяет опускать количество выделяемых элементов в new[]:
char* p = new char[];

Возникает два вопроса:
  • сколько памяти выделяется?
  • для чего это нужно?
Попытаемся ответить на эти вопросы.

Ответ на первый вопрос - нисколько. И сразу же переходим ко второму вопросу.
Ответ на второй вопрос - это использование уже выделенной памяти для новых объектов.

По сути это особая форма оператора new, называемая placement new. Данный оператор не выделяет память, а получает своим аргументом адрес на уже выделенную каким-либо образом память (например, в стеке или через malloc).

Происходит размещение (инициализация) объекта путем вызова конструктора, и объект создается в памяти по указанному адресу. Часто такой метод применяют, когда у класса нет конструктора по умолчанию и при этом нужно создать массив объектов. Ниже приведён простой пример:

#include <new>
#include <iostream>

class A
{
private:
 int _x;
 A() {
  std::cout << "A() at " << (void*) this << std::endl;
 }
public:
 A(int x) {
  _x = x;
  std::cout << "A(" << x << ") at " << (void*) this << std::endl;
 }
 ~A() {
  std::cout << "~A() with _x=" << _x << " at " << (void*) this << std::endl;
 }
};

int main()
{
 const int n = 3;
 // выделить память под A, но не вызывая конструктора
 char* memory[ n*sizeof(A) ];
 A* placementMemory = static_cast<A*>(static_cast<void*>(memory));

 // вызвать конструкторы объектов (без выделения памяти, но с использованием выделенной)
 for (int i=0; i<n; i++)
  // new (указатель_на_область) вызов_конструктора;
  new (placementMemory+i) A(i+3); // конструктор может быть с параметрами или без

 // следует вручную вызвать деструкторы
 for (int i=0; i<n; i++)
  placementMemory[i].~A();

 return 0;
}

Результат работы:

Полезно будет почитать http://www2.research.att.com/~bs/bs_faq2.html#placement-delete (Bjarne Stroustrup's C++ Style and Technique FAQ)

Комментариев нет:

Отправить комментарий