Default-Initialization vermeiden
-
DaPeter schrieb:
Hm, trotzdem stürzt es mir dann ab, wenn ich mit [] etwas zuweisen will (nur bei Visual C++).
Nicht "trotzdem" sondern "weil". Da worauf du mit
[]zugreifen willst, da ist noch nix. Du musst dann schon Objekte deiner Vorstellung mit Hausnummerpush_back()hintun.Beantworte die Frage von firefly!
-
Ich möchte einfach die default-init vermeiden aus Performancegründen (ich hab die Zeit gemessen), da der vector recht groß ist. Ich möchte danach aber trotzdem mit operator[] nutzen können. reserve() ändert nur die capacity, nicht die size, daran scheint sich Visual C++ zu stören.
Folgendes funktioniert:
T * v = new T[v]; // .. // operator[] funktioniert // ... // delete [] v;Das ist performancemäßig deutlich besser, da nicht initialisiert wird. Ich kann das natürlich wrappen in nen struct, damit ich das genauso benutzen kann, wie einen std::vector, aber ich will den Code nicht unnötig aufblähen.
Deswegen möchte ich lieber den normalen std::vector nutzen und frage deswegen hier, ob ich irgendwas übersehen habe, um das zu tun.
-
Wie schaut denn so eine
v[x]-Zeile aus?
-
DaPeter schrieb:
Das ist performancemäßig deutlich besser, da nicht initialisiert wird.
Nein, für jedes Element wird der default-Konstruktor aufgerufen*. Nichts anderes macht das mit std::vector auch.
*Wenn du das nicht glaubst: delete den Default-Konstruktor von T. Kompiliert nicht.
-
Es macht auch wenig Sinn, ein uninitialisiertes Objekt im Programm zu haben.
Lediglich bei den primitiven Datentypen ist es sinnvoll, weil man damit ein Array in konstanter Zeit reservieren kann und nicht noch alles initialisieren muss, allerdings sind die standardlibraries heutzutage vermutlich in der Lage diese Optimierung in std::vector ebenfalls auszufuehren.
-
Du hast Recht, sry. Ich habe jetzt mal etwas rumgegoogelt. Wenn ich new benutze, dann wird default-initialisiert. Wenn ich std::vector benutze, dann wird immer value-initialisiert, auch wenn ich keinen expliziten Wert angeben. (http://stackoverflow.com/questions/7218574/avoiding-default-construction-of-elements-in-standard-containers)
Da gibts scheinbar keine schöne bereits in C++ eingebaute Lösung dafür.
-
Doch, zur Not speicherst du halt Pointer im vector (d.h. std::unique_ptr).
Aber wie alle vor mir schon gesagt haben, was genau hast du vor?
-
DaPeter schrieb:
Da gibts scheinbar keine schöne bereits in C++ eingebaute Lösung dafür.
Natürlich nicht!
Du willst dass der Konstruktor eines Elementes aufgerufen wird, bevor du es verwendest. Darauf verlasen sich nicht triviale Typen!
Wenn du nicht willst, dass direkt für alle Elemente ein Konstruktor aufgerufen wird, nutz reserve. Dann kannst du das gezielt steuern. Aber aufgerufen werden muss der, bevor die Typen verwendest.Beschreib nochmal, was genau du vorhast.
-
Ich denke mal, sein Problem ist, dass bei
std::vector<int> v(100);
alle Werte mit 0 initialisiert werden. Bei
int* v = new int[100]
bleiben die Werte uninitialisiert. Die 0-Initialisierung beim vector wirkt sich nachteilig auf die Laufzeit aus.
push_back vom vector kann man nur verwenden, wenn man das Array sequentiell füllt. Wenn man beispielsweise eine inverse Permuation eines anderen Arrays berechnen möchte, hilft einem das nicht weiter.
Man könnte so eine Konstruktion wie
struct A {int x};
verwenden, aber die Verwendung im Code ist dann etwas umständlicher (da man immer ".x" schreiben muss). Oder man überläd alle Operatoren von int für A, aber das ist auch sehr viel Arbeit.
Ich glaube eine schöne und kurze Lösung gibt es nicht.
-
DaPeter schrieb:
Nabend,
std::vector<T> big_vector(n)Kann ich hier irgendwie vermeiden, dass sämtliche n Einträge initialisiert werden?
Vielleicht mit einem custom allocator, der nur alloziert? (damit kenne ich mich nicht aus).
Ich kann natürlich einfach ein normales mit new erzeugtes array wrappen, aber ich will den Code nicht unnötig aufblähen.Du musst die Initialisierung halt inline und schnell machen. Anders geht es nicht.
Wenn Du einen std::vector mit n Elementen hast, dann hast Du die Garantie, dass die Elemente auch funktionieren. Und das kann nur ein Konstruktor leisten.
Denke mal daran, dass T ja auch ein Objekt sein kann, der im Destruktor etwas mit seinen Elementen macht. Ist da ein Zeiger dabei, der nicht initialisiert ist, dann gibt es Probleme.
Du kannst übrigens auch dem Konstruktor von std::vector einen 2. Parameter mit geben, der zum initialisieren verwendet wird. Beispielsweise:
std::vector<MyClass> big_vector(4711, MyClass::null())Dann wird nicht der Default-Konstruktor aufgerufen sondern der copy-Konstruktor. Das könnte unter Umständen billiger sein.
Eine andere Möglichkeit ist, wie bereits erwähnt mit
reserveSpeicher bereits zu reservieren. Dann kannst Du aber nicht einfach auf die Elemente zugreifen. Aber Du kannst sie durch push_back (oder emplace_back) bei Bedarf erzeugen, ohne dass eine Allokation des Vectors statt findet.