new[]-array und konstruktoren
-
camper schrieb:
Ohne Klammern (new T[...]): Defaultkonstruktor wird aufgerufen, wenn T kein POD ist.
Mit Klammern ( new T[...]() ): Defaultkonstruktor wird immer aufgerufen.Gibts überhaupt Fälle, wo das einen Unterschied macht? Schließlich werden PODs doch gar nicht initialisiert, oder etwa doch

-
Badestrand schrieb:
camper schrieb:
Ohne Klammern (new T[...]): Defaultkonstruktor wird aufgerufen, wenn T kein POD ist.
Mit Klammern ( new T[...]() ): Defaultkonstruktor wird immer aufgerufen.Gibts überhaupt Fälle, wo das einen Unterschied macht?
Immer dann, wenn ich initialisierte PODs haben will? Defaultinitialisierung bei PODs ist Zero-Initialisierung - bei einer POD-Struktur werden also alle Member mit 0(geeignet konvertiert) initialisiert.
wenn ich new char[...] schreibe, erhalte ich einen Block mit unbekanntem Inhalt. bei new char[...]() steht überall 0 drin.
-
Oh, was man noch alles lernen kann

-
und mit new[](bla, bla)
ruf ich andere Konstruktoren auf?
Das geht?
Dachte, das würde er nicht wollen.
Probier ich mal aus, vielen Dank!
Sören
-
soerenP schrieb:
und mit new[](bla, bla)
ruf ich andere Konstruktoren auf?leider nicht.
-
Scheint nicht zu gehen

"Angabe der Initialisierung für Felder nicht möglich."
Führt da kein weg an einer nachfolgenden Schleife mit gnz vielen init(bla, bla) aufrufen vorbei?
Grüße
Sören
-
soerenP schrieb:
Führt da kein weg an einer nachfolgenden Schleife mit gnz vielen init(bla, bla) aufrufen vorbei?
Klar, verwende einen vernünftigen Container, der seine Elemente gleich initialisieren kann

//aufwendig und fehleranfällig: meineKlasse* data = new meineKlasse[100]; for(int i=0;i<100;++i) data[i]=meineKlasse(x,y); //besser: std::vector<meineKlasse> data(100,meineKlasse(x,y));
-
soerenP schrieb:
Scheint nicht zu gehen

"Angabe der Initialisierung für Felder nicht möglich."
Führt da kein weg an einer nachfolgenden Schleife mit gnz vielen init(bla, bla) aufrufen vorbei?
Grüße
SörenAuf (großen) Umwegen geht vieles, allerdings ist das generisch kaum in den Griff zu kriegen:
struct T; extern T proto; struct T { T(const T& = proto) : /* ... */ {} // Copy- und Default-ctor explicit T(... ) /* ... */ // ... }; T proto( ... ); // Defaultkonstruktor vermeiden. // ... proto=... new T[...]() // Alle Elemente werden als Kopie von proto initialisiertso oder ähnlich geht das schon, ist aber ziemlich umständlich und hässlich
Der normale Weg ist die manuelle Allokation und dann placement new in einer Schleife. Ob man darauf dann delete[] anwenden darf, ist dabei allerdings etwas problematisch - zumindest in generischem Code sollte man das unterlassen.
-
Oha, tief in die Trickkiste gegriffen. Vielen Dank. Ich bekomms auch so hin;)
Tschö
Sören
-
ich hab mal ne kleine Templatefunktion geschrieben, die ein new[] mit beliebigem Konstruktoraufruf durchführt (löschen wie gehabt mit delete[]):
#include <cstddef> #include <memory> #include <ostream> #include <iostream> template <typename T> T* call_operator_new_array(std::size_t n, ...) { return static_cast< T* >( ::operator new[]( n ) ); } template <typename T> T* call_operator_new_array(std::size_t n, int(*)[sizeof(T::operator new[]( n ))]) { return static_cast< T* >( T::operator new[]( n ) ); } template <typename T> void call_operator_delete_array(T* p, ...) { ::operator delete[]( p ); } template <typename T> void call_operator_delete_array(T* p, int(*)[sizeof(T::operator delete[]( p ),0)]) { T::operator delete[]( p ); } template <typename T> T* new_array(std::size_t n) { T* p = call_operator_new_array< T >( n, 0 ); std::size_t i = 0; try { for ( ; i < n; ++i ) ::new ( p + i ) T(); return p; } catch (...) { for ( ; i; ) p[ --i ].~T(); call_operator_delete_array( p, 0 ); throw; } } template <typename T, typename U1> T* new_array(std::size_t n, U1 arg1) { T* p = call_operator_new_array< T >( n, 0 ); std::size_t i = 0; try { for ( ; i < n; ++i ) ::new ( p + i ) T( arg1 ); return p; } catch (...) { for ( ; i; ) p[ --i ].~T(); call_operator_delete_array( p, 0 ); throw; } } template <typename T, typename U1, typename U2> T* new_array(std::size_t n, U1 arg1, U2 arg2) { T* p = call_operator_new_array< T >( n, 0 ); std::size_t i = 0; try { for ( ; i < n; ++i ) ::new ( p + i ) T( arg1, arg2 ); return p; } catch (...) { for ( ; i; ) p[ --i ].~T(); call_operator_delete_array( p, 0 ); throw; } } // usw. struct T {}; struct U { static void* operator new[](std::size_t n) { std::cout << "U::operator new[]" << std::endl; return ::operator new[]( n ); } static void operator delete[](void* p) { std::cout << "U::operator delete[]" << std::endl; ::operator delete[]( p ); } }; int main() { new_array<int>(10); new_array<T>(10); new_array<U>(10); }dummerweise klappt es nicht mit vc; g++ ist ungetestet, comeau hat keine Probleme. vielleicht hat ja jemand eine Idee, wie man das Ganze mit vc zum laufen kriegt. Allgemein besteht die Problematik darin, abhängig davon, ob ein Ausdruck wohlgeformt ist oder nicht, eine entsprechende Überladung auszuwählen.