Konstruktor und Destruktor
-
hustbaer schrieb:
placement delete
Was ist denn das?
-
LordJaxom schrieb:
Was ist denn das?
Zu jedem eigenen definiertem placemente new Operator sollte man auch ein placemente delete schreiben:
void* operator new(std::size_t size, Pool& pool) { return pool.alloc(size); } void operator delete(void* ptr, std::size_t size, Pool& pool) { pool.dalloc(ptr, size); }Der Grund ist der folgende:
class MyClass { public: MyClass() { throw std::exception("bum!"); } }; Pool pool; MyClass* myObject = new (pool) MyClass();Der Konstruktor wirft eine Exception. Damit der angeforderte Speicher vom placement new auch wieder sauber freigegeben wird, muss ein placement delete existieren.
Wenn man das Ding übrigens manuell aufrufen will, dann geht dies nur so:operator delete(myObject, pool);hustbaer schrieb:
sollte man mit placement new erzeugte objekte nicht auch mit placement delete wieder freigeben?
Man hat im placement
deleteOperator allerdings keine Typinformationen mehr, daher kann man keinen Destruktor mehr aufrufen. Dies muss irgendwie davor geschehen.Grüssli
-
hustbaer schrieb:
sollte man mit placement new erzeugte objekte nicht auch mit placement delete wieder freigeben?
Nein. Das placement new verwendet man meistens nur, um den Ctor explizit aufzurufen. Den Dtor ruft man explizit mit objekt.~Klassenname() auf.
Manchmal verwendet man das placement new auch, um einen Hint zu geben, zum Beispiel wer der später löschenden Thread wohl sein wird oder in der Nähe welchen anderen Speicherblocks man zu liegen kommen mag für mehr Lokalität. So ein Hint ist aber kein richtiger Piratenkodex, sondern mehr so eine Richtlinie. Und gehinteter Speicher mut mit normalem delete wieder freigegeben werden können.
Manchmal benutzt man placement new für memory pooling. Dann braucht man kein delete, weil der Witz ja ist, daß man, sobald die Antwort versichickt wurde, nachher den ganzen Pool wegschmeißt.
Statt pooling kann man's auch machen, um push_back zu beschleunigen-ersetzten ohne perfect forwarding. Leider ist bei Template-Pools der GCC dumm und kann kein placement delete. Aber mit c++0x ist der Druck nicht mehr da, sowas zu machen. Auch hier würde kein delete nötig sein, der z.B. vector das alles auch ohne delete gut managen kann.
Ich erinnere mich noch, daß ich dem delete auch Hints mitgeben wollte. Aber irgendwie ist da auch der Druck weg. Es gibt fettere Tricks um Speed zu machen. Und im besonderen Fall, daß man die Objektgröße haben muß, für den small object allocator, so kriegt man die zum Glück kostenlos oder zu geringeren Kosten als man es per Hand könnte.
-
Achja, es gibt ja keine Placement-Delete-Expression.
Den Operator manuell aufzurufen hat natürlich keinen Sinn, das führt einem den Destruktor ja nicht aus.
-
Das placement delete gibt es übrigens sehr wohl (siehe <new>) - es macht nur nichts:
inline void *__CRTDECL operator new(size_t, void *_Where) _THROW0() { // construct array with placement at _Where return (_Where); } inline void __CRTDECL operator delete(void *, void *) _THROW0() { // delete if placement new fails }(ausm msvc 9.0)
Falls das nicht vorhanden ist (aber man placement new nutzt), gibts auch mindestens ne warning - vll so gar nen error - weiß ich gar nicht mehr genau und bin auch zu faul... ^^
bb
-
@unskilled:
Klar gibt's das, aber es gibt keine "placement delete expression" analog zu "new (p1, p2, ...) T".Unterschied: der (placement oder nicht) new Operator besorgt nur Speicher. Eine new Expression ruft den new Operator auf und danach den Konstruktor.
Analog dazu gibt der (placement oder nicht) delete Operator nur Speicher frei. Da es aber nur eine normale delete Expression gibt, nicht aber eine placement Form, kann man über eine delete Expression auch kein placement Delete machen. Wenn man es braucht, muss man erst direkt den Destruktor aufrufen und dann den passenden placement-Delete Operator.
Und ein placement delete Operator muss nicht nichts tun.
Sinnvollerweise sollte der (void*, void*) placement delete Operator nichts tun, da der new (size_t, void*) Operator auch nichts tut.Du kannst aber jederzeit einen new(size_t, MyAllocator*) Operator basteln, der über MyAllocator Speicher besorgt.
Dazu solltest du dann einen placement delete Operator delete(void*, MyAllocator*) machen, der den Speicher auch wieder brav freigibt. Hier einen "leeren" Operator delete(void*, MyAllocator*) zu machen wäre ein grober Fehler.@volkard:
Mal abgesehen davon was Sinn macht oder nicht...
Man kann placement new für alles mögliche verwenden. Und da gibt es durchaus Varianten wo man weder das delete einfach weglassen kann, noch das "normale" delete verwenden. Wo man also genau das machen muss, was eine placement delete Expression machen würde, wenn es denn eine gäbe.Das nächstliegende Beispiel wäre wohl ein auf irgendwas spezialisierter Allokator, dem man ganz "klassisch" die freigewordenen Objekte wieder zurück geben muss.
Wie gesagt, mal abgesehen davon ob es Sinn macht oder nicht. Das ist wieder ein anderes Thema. (Und wie man daraus schliessen kann dass ich nicht wusste dass es keine placement delete Expression gibt, habe ich sowas auch noch nie gebraucht/verwendet).