Frage zu new und Konstruktoren
-
Ich habe gerade etwas Code für eine Speicherverwaltung vor mir und würde gerne wissen ob ich die Auswirkung auf Klassen und Konstruktoren richtig verstehe.
Der Code beinhaltet eine Funktion der man die gewünschte Speichergröße in Byte gibt und die dann auf einen void* den Speicher mittels ::operator new(size) packt und dann den Poinetr zurückliefert. Dazu passend ist auch eine Funktion die die einen void* auf den Speicherbereich erwartet und ihn dann mittels ::operator delete(void*) freigibt.
Sehe ich das richtig das bei dieser Art und weise kein Konstruktor aufruf erfolgen würde wie er bei new MyClass zB erfolgen würde und das entsprechend kein Destruktor Aufruf beim freigeben erfolgt, da ja eigentlichd er Zeiger nur anders Interpreteirt werden würde? Was mich zusätzlich interessieren würde, erwischt ::operator delete(void*) überhaupt den gesammten Speicherplatz?
-
Xebov schrieb:
[1] Sehe ich das richtig das bei dieser Art und weise kein Konstruktoraufruf erfolgen würde wie er bei new MyClass zB erfolgen würde und
[2] das entsprechend kein Destruktor Aufruf beim freigeben erfolgt, da ja eigentlichd er Zeiger nur anders Interpreteirt werden würde?
Was mich zusätzlich interessieren würde:
[3] erwischt ::operator delete(void*) überhaupt den gesammten Speicherplatz?1 ja
2 ja
3 jaman tut das in etwa so:
int main() { TMyObject *arr; size_t len = 5; alloc (arr, len); try { init_with_value (arr, len, TMyObject); } catch (...) { dealloc (arr, len); throw; //einfach weiterwerfen... } /* hier dürfen wir endlich mit unserem array rumspielen ^^ */ dealloc (arr, len); //und rufen zum schluss wieder die fkt zum freigeben des speichers auf } template <typename ValueType> void alloc(ValueType * &values, size_t count) { try { //wir versuchen values = reinterpret_cast <ValueType*> (operator new[] (sizeof(ValueType) * count)); //ein array für 'count' elemente vom typ ValueType zu erstellen - operator delete[] wird genau wieder so viele bytes freigeben, wie wir hier angefordert haben } catch(...) { values = nullptr; //wenn das schiefläuft, ist die allokation schiefgelaufen - wir setzen also den ptr auf 0 throw; //...und werfen die exception weiter... } } template <typename ValueType> void dealloc(ValueType * &values, size_t count) throw() //ich geh einfach mal davon aus, dass der destruktor des objekts keine exception werfen darf... { if(!values) return; //wenn values = 0 ist, gibts nix zu tun... for (ValueType *iter = values, *end = values+count; iter != end; ++iter) { iter->~ValueType(); //hier wird der destruktor von hand aufgerufen - da operator delete[] (void*) ihn nicht aufrufen kann, da der keine typinformationen hat - und somit nicht wüsste, wo er den finden sollte } operator delete[] (values); //und dann der operator delete aufgerufen, der einfach nur die anzahl an bytes, die wir oben mit operator new[] angefordert haben, wieder frei gibt values = nullptr; //am ende setzen wir values noch auf 0 (bzw nullptr, weil wir vorbildlich sind und schon nullptr nutzen ^^) - auch, wenn das nicht unbedingt notwendig wäre... } template <typename ValueType> void init_value(ValueType *destination, size_t &count, ValueType fill_with) { //kein plan, ob man das wirklich so macht - aber was besseres ist mir nicht eingefallen... size_t left (count); try { for (; left != 0; --left, ++destination) { destination = new (destination) ValueType (fill_with); //das placement new, was den copy-ctor jedes mal wieder aufruft } } catch (...) { //wenn der ctor eine exception wirft, müssen wir iwie danach wissen, wie viele elemente gelöscht werden sollen count -= left; //das sagen wir hier - deshalb auch oben die nicht-const ref throw; //und werfen die exception weiter... } }bb
-
Besten dank das is genau das was ich wissen wollte.