std::vector befüllen ohne copy constructor?
-
cl90 schrieb:
Ich hab es jetzt letztendlich auf dem Heap gelöst. also
vector.pushback(new bla());
mit entsprechenden deletes an anderen stellen.Och nö! Der Ansatz ist sehr fehleranfällig bzgl Speicherlecks. Dann nimm doch wenigstens
boost::ptr_vector
, wenn du schon keine C++11 Features benutzen willst/kannst.
-
kkaw schrieb:
cl90 schrieb:
Ich hab es jetzt letztendlich auf dem Heap gelöst. also
vector.pushback(new bla());
mit entsprechenden deletes an anderen stellen.Och nö! Der Ansatz ist sehr fehleranfällig bzgl Speicherlecks. Dann nimm doch wenigstens
boost::ptr_vector
, wenn du schon keine C++11 Features benutzen willst/kannst.Ich bin auch nicht zufrieden damit...
Aber sag mir, kann ich mein Projekt ohne viel aufwand einfach auf C++11 umstellen?
Ich habe jetzt schon so viele externe Abhängigkeiten und weit mehr als 5000 Zeilen code in über 80 files... Ich weiß nicht wie einfach man das umstellen kann.
Ich habs mir vorerst nur auf meien ToCheck Liste für das nächste Projekt gesetzt.prt_vector regelt das delete selbst?
Weil das wäre kein Problem. Ich hab Boost x64 bereits im Projekt.
-
Du musst nichts umstellen (ausser vielleicht den Compiler), C++11 ist abwärtskompatibel -- von unbedeutenden Features mal abgesehen.
Ja,
boost::ptr_vector
räumt selbst auf. Ich persönlich bin aber spätestens seit C++11 kein Fan mehr von den Pointer-Containern, siehe hier.
-
ok dann werd ich mal lesen wie das geht mit dem umstieg.
-
Nexus schrieb:
Ja,
boost::ptr_vector
räumt selbst auf. Ich persönlich bin aber spätestens seit C++11 kein Fan mehr von den Pointer-Containern, siehe hier....wobei ich im Falle von
vector<unique_ptr<T>>
die extra Indirektion, die man da durchführen muss, schon nervig finde. Das const wird auch leider nicht propagiert:void foo(vector<unique_ptr<int>> const& vec) { if (!vec.empty()) { *vec.front() += 17; // klappt! } }
Wenn Du "unhandliche Objekte" nur deswegen einzeln im Heap anlegst und die Adresse in einem unique_ptr speicherst, damit das Speichern im Vektor "effizienter" wird, ist diese Zeiger-Semantik eigentlich nicht das, was man haben will.
Klar, ich kann mir ausgehend von
vector<unique_ptr<T>>
immer noch perboost::indirect_iterator
zwei Iteratoren bauen, wo ich diese nervige extra Indirektion nicht mehr brauche und worüber auch einconst
hinzugefügt werden kann. Das ist schon mal was.Aber vielleicht wäre da ein anderer Wrapper nicht ganz verkehrt. Ich habe in meiner Sammlung noch eine Kuh (copy-on-write). Hier nur mal eine vereinfachte und ungetestete Skizze davon:
template<class T> class cow { public: cow() { static const auto def = make_shared<T>(); // cached default ptr = def; } cow(T const& x) : ptr(make_shared<T>(x)) {} cow(T && x) : ptr(make_shared<T>(std::move(x))) {} template<class U, class...More ,class=typename std::enable_if< !std::is_convertible<U,cow const&>::value && std::is_constructible<T,U,More...>::value >::type > cow(U && x, More && ... xx) : ptr(make_shared<T>(forward<U>(x),forward<More>(xx)) {} T const& read() const {return *ptr;} T const& operator*() const {return *ptr;} T const* operator->() const {return ptr.get();} operator T const&() const& {return *ptr;} operator T const&() const&& = delete; // zu unsicher T& write() { if (!ptr.unique()) { ptr = make_shared<T>(*ptr); } assert(ptr.unique()); return *ptr; } private: shared_ptr<T> ptr; };
was man dann so nutzen könnte:
vector<cow<unhandlicher_typ>> vec; vec.emplace_back(dies,und,jenes); ... for (auto& x : vec) { x.write().veraendere_dich(1,2,3); } for (unhandlicher_typ const& x : vec) { cout << x.get_something() << endl; }
Und sonst könnte man ja auch einfach mal
std::deque<T>
mitemplace
ausprobieren ohneunique_ptr
und ohnecow
. Da sollte auch nicht so viel kopiert werden. Und das wäre mein aktueller Tipp für cl90: Probier malstd::deque
und/oderemplace
aus.cl90 schrieb:
ok dann werd ich mal lesen wie das geht mit dem umstieg.
Ich glaube, beim Microsoft Compiler musst du gar nix besonderes machen. Er unterstützt automatisch schon C++11 Features, sofern einigermaßen aktuell. Beim GCC kommt es auf die Version an. Ggf brauchst du den Compilerschalter "-std=c++0x" oder "-std=c++11".