Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > placement new


Автор: d06osipov 21.12.2007, 11:20
Я использую placement new, например так:
Код

char* ptr;
ptr=new char[sizeof(T)];
new(ptr) T;

Вопрос: как теперь вызвать delete, чтобы потом можно было снова по этому адресу объект создать?

И ещё. Верно ли, что placement new и delete гораздо более эффективны, чем обычные, потому что не надо искать свободное место в памяти?

Автор: Lazin 21.12.2007, 11:25
Код

ptr->~T();

Цитата(d06osipov @  21.12.2007,  11:20 Найти цитируемый пост)
И ещё. Верно ли, что placement new и delete гораздо более эффективны, чем обычные, потому что не надо искать свободное место в памяти? 

зависит от того где ты эту память собираешься брать))

Автор: d06osipov 21.12.2007, 11:32
1. А хорошо ли напрямую вызывать деструктор, нет ли более аккуратного способа?

Кроме того, помоему надо 
Код

reinterpret_cast<T*>(ptr)->~T();


2. Память я выделяю один раз обычным new. Правда ли, что потом placement new не делает ничего существенного, кроме вызова конструктора и инициализации локальных членов объекта (то есть время работы placement new несущественно больше времени работы конструктора и времени на инициализацию локальных членов).

Автор: Lazin 21.12.2007, 12:23
Код

char* ptr;
ptr=new char[sizeof(T)];
T* pt = new(ptr) T;

pt->~T();

Цитата(d06osipov @  21.12.2007,  11:32 Найти цитируемый пост)
Правда ли, что потом placement new не делает ничего существенного, кроме вызова конструктора и инициализации локальных членов объекта

да правда, это бывает иногда необходимо, например для использования какого то блока памяти(выделенного заранее), или можно реализовать необычную стратегию управления памятью(хотя для этого обычно перегружают new delete)

Автор: d06osipov 21.12.2007, 14:18
Цитата(Lazin @ 21.12.2007,  12:23)
Код

pt->~T();


А такой вызов деструктора будет уничтожать локальные члены объекта *pt? Скажем, если pt->field объект некоторого класса, то вызов pt->~T() вызовет ли деструктор pt->field (как это происходит при обычном удалении)?

Автор: Alek86 21.12.2007, 14:26
да, на то он и деструктор

Автор: Daevaorn 21.12.2007, 14:49
d06osipov, так лцучше не писать. зачем тебе морока с char?
Код

T* ptr;
ptr=operator new(sizeof(T));
new(ptr) T;
//...
ptr->~T();

Автор: d06osipov 21.12.2007, 15:59
Цитата(Daevaorn @ 21.12.2007,  14:49)
d06osipov, так лцучше не писать. зачем тебе морока с char?
Код

T* ptr;
ptr=operator new(sizeof(T));
new(ptr) T;
//...
ptr->~T();

Спасибо.

Но всё-таки, вызов деструктора, есть нечто большее, чем вызов обычной функции, так?

Автор: Lazin 21.12.2007, 16:49
Цитата(d06osipov @  21.12.2007,  15:59 Найти цитируемый пост)
Но всё-таки, вызов деструктора, есть нечто большее, чем вызов обычной функции, так? 

при вызове delete происходит неявный вызов деструктора, а код деструктора выполняет удаление всех членов класса, для них то-же вызывается деструктор, и тд. В случае размещающего оператора new вызывать delete не нужно, но удалять память выделенную под члены класса все равно придется, поэтому нужно его вызвать напрямую.

Автор: d06osipov 21.12.2007, 18:40
Цитата(Lazin @ 21.12.2007,  16:49)
при вызове delete происходит неявный вызов деструктора, а код деструктора выполняет удаление всех членов класса, для них то-же вызывается деструктор, и тд

Уверены, что именно код деструктора выполняет удаление всех членов, а не код delete?

Добавлено через 13 минут и 50 секунд
Всем спасибо, я убедился сам

Вот программа:
Код

#include <iostream>
using namespace std;

struct A
{ A()
  { cout<<"A construct"<<endl;
  }
 ~A()
  { cout<<"A destruct"<<endl;
  }
};

struct B
{ A a;
  
  B()
  { cout<<"B construct"<<endl;
  }
 ~B()
  { cout<<"B destruct"<<endl;
  }

};

int main()
{ B* b=reinterpret_cast<B*>(operator new(sizeof(B)));
  new(b) B;
  b->~B();
  operator delete((void*)b);
  return 0;
}


Вывод (g++) 
Код

A construct
B construct
B destruct
A destruct


Замечание. B*b=operator new(sizeof(B)); не работает, потому что operator new возвращает void*.

Я надеюсь, что это стандартный приём, и будет работать так на всех компиляторах.

Автор: onsql 21.12.2007, 19:49
А как в эту теорию впишется результат работы такого кода?
Код

#include <iostream>
using namespace std;

struct A
{ A()
  { cout<<"A construct"<<endl;
  }
 ~A()
  { cout<<"A destruct"<<endl;
  }
};

struct B
{ A a;
  
  B()
  { cout<<"B construct"<<endl;
  }
 ~B()
  { cout<<"B destruct"<<endl;
  }

};

int main()
{
  void * mem = malloc(sizeof(B));
  B * bObj = new(mem) B();
  bObj->~B();
  free(mem);

  return 0;
}


Вывод на экран, аналогичен твоему примеру. 

Автор: d06osipov 24.12.2007, 16:19
Хотя я не сторонник дедовских способов выделения памяти, в данном случае меня соверщенно не волнует этот процесс. placement new совершенно всё равно, каким именно образом выделена та память, куда будет размещён объект. 

Автор: Earnest 24.12.2007, 16:30
Цитата(onsql @  21.12.2007,  20:49 Найти цитируемый пост)
Вывод на экран, аналогичен твоему примеру. 

Прекрасно вписывается. А что смущает?

Автор: onsql 24.12.2007, 16:31
Ну наверное я просто невнимательно прочитал.  Просто я так понял, что вот эта фраза
Цитата

Уверены, что именно код деструктора выполняет удаление всех членов, а не код delete?

относилось к тому, что в приведенному примере, именно благодаря вызову delete были вызваны деструкторы внутренних полей объекта b. На самом деле они были удалены в момент вызова  
Код

b->~B();

Автор: Earnest 24.12.2007, 17:19
Да, конечно. А деструктор был вызван благодаря delete  smile (но никто и не говорил, что это единственный способ его вызвать)

Автор: onsql 24.12.2007, 17:38
Разве? Так я вроде бы как раз и привел пример, показывающий что это не так, заменив delete на free. Ведь free никаких деструкторов не вызывает? smile)

Автор: Earnest 24.12.2007, 18:25
В твоем примере деструктор вызывается явно, а в предыдущем - через delete... я про него...

Автор: onsql 24.12.2007, 18:31
Не а. В исходном примере он тоже вызывается явно. А потом идет delete который освобождает память, но не вызывает деструктор B. Или я чего то не понимаю?
Код

int main()
{ B* b=reinterpret_cast<B*>(operator new(sizeof(B)));
  new(b) B;
  b->~B();
  operator delete((void*)b);
  return 0;
}

Автор: Earnest 24.12.2007, 20:36
Я, честно говоря, по диагонали код смотрела.
Но в приведенном тобою сейчас фрагменте фактически тот же free вызывается - т.к. void очевидно, никакого деструктора не имеет. 
А что касается темы, placement new, то ему собственно delete и не нужен... Delete, к сожалению, один на всех, и не может зависеть от того, какой new применялся...
Короче, я уже не понимаю, о чем спорим...

Автор: onsql 24.12.2007, 21:05
Ну да,  просто топикстартер сомневался, кто удаляет все члены данные объекта в его примере. А спорить то и не о чем, тем более автор давно тему закрыл smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)