vector hinzufügen ohne objekt zu kopieren (ggf. refcount++)
-
Hallo,
gibt es eine Möglichkeit ein zuvor erstelltes Objekt zu einem Vector hinzuzufügen, ohne dass es kopiert wird und somit eine neue Speicheradresse bekommt?Sinn des Ganzen:
ich habe ein Objekt (TElement), dieses besitzt eine Liste (vector) von anderen Objekten (TConnection).
beim Erstellen von TElement werden diverse TConnection erzeugt und dabei der this-pointer des TElement in den TConnection's gespeichert.wenn ich dieses TElement in einem Vector speichere, passen scheinbar die TElement-Pointer in den TConnections nicht mehr.
Wie kann ich dieses Problem lösen?
Gruß Frank
-
Mit Zeigern oder Smart-Pointern auf Objekte arbeiten. Z.B.
std::vector<std::unique_ptr<T>>oderboost::ptr_vector<T>.Oder du schaust, dass die Connections beim Kopieren des Objekts ebenfalls angepasst werden.
-
Kopierkonstruktor + op= für TElement implementieren und dort den TConnections im Vector den Zeiger neu zuweisen.
Oder so implementieren, dass die TConnections nichts vom TElement wissen müssen.
-
bei dem unique_ptr muss ich sicherlich den refernz-counter erhöhen (wenn es bei normalen klassen sowas gibt), oder? bzw. mich um die komplette speicherverwaltung kümmern (new/delete)
wie kann ich letzteres abfangen?
Gruß Frank
-
Musst du beides nicht. Dazu ist er schließlich da.
-
laut http://en.cppreference.com/w/cpp/memory/unique_ptr muss ich <memory> einbinden...
dann müsste ich das doch so definieren:
typedef std::vector<std::unique_ptr<TElement>> TElementList;aber ich bekomme die Fehlermeldung
‘unique_ptr’ is not a member of ‘std’was mache ich falsch?
-
Vermutlich musst du bei deinem Compiler erst den C++11 Modus einschalten.
-
nutze den g++ (4.4.3) unter linux
http://gcc.gnu.org/projects/cxx0x.html
Important: GCC's support for C++11 is still experimental.trotzdem hab ichs mal probiert:
g++ -Wall -std=c++11 platine.cpp -o platine `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0`cc1plus: error: unrecognized command line option "-std=c++11"
in der man-page finde ich den 11er nicht nur 0x
gibts nix vergleichbares zu unique_ptr im c++ standard?
-
C++0x = C++11. Also stimmt -std=c++0x schon.
-
jetzt findet er es zumindest mal...
aber scheinbar ändert sich da auch mein aufruf...
Fehlermeldung:
error: no matching function for call to ‘std::vector<std::unique_ptr<TConnection, std::default_delete<TConnection> >, std::allocator<std::unique_ptr<TConnection, std::default_delete<TConnection> > > >::push_back(TConnection&)’
/usr/include/c++/4.4/bits/stl_vector.h:733: note: candidates are: void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = std::unique_ptr<TConnection, std::default_delete<TConnection> >, _Alloc = std::allocator<std::unique_ptr<TConnection, std::default_delete<TConnection> > >]
/usr/include/c++/4.4/bits/stl_vector.h:746: note: void std::vector<_Tp, _Alloc>::push_back(_Tp&&) [with _Tp = std::unique_ptr<TConnection, std::default_delete<TConnection> >, _Alloc = std::allocator<std::unique_ptr<TConnection, std::default_delete<TConnection> > >]code:
TElement::TElement(...) { ... TConnection c(fPlatine,this,id,s); Connections.push_back(c); //diese zeile wird bemängelt}
-
Du hast ja jetzt auch keine Values mehr in deinem vector, sondern unique_ptr!
-
über gebe ich dann die Speicheradresse??
also push_back(&c)?
ggf. mit cast auf unique pointer oder wie läuft das dann?
wie bekomme ich mein Objekt wieder raus und wie ist das mit der Speicherfreigabe?
-
Du musst die Objekte dynamisch anlegen. Freigegeben werden sie automatisch, da es sich um einen Smart-Pointer handelt.
std::unique_ptr<TConnection> c(new TConnection(fPlatine,this,id,s)); Connections.push_back(c);
-
mhm, kann ich da einfach per list[i] auf die TConnections zugreifen?
habe überlegt, obs nicht sinnvoller wäre die ganze pointer-verarbeitung aus dem constructor rauszuverlagern (init-prozedure), die ich auf das listen-element ausführe.
Pseudocode:
std::vector<TConnection> TConnectionList; TConnectionList clist; TConnection c(); clist.push_back(c); clist[clist.size()-1].init(...)
-
ich lasse jetzt die Berechnungen das übergeordnete TElement machen und kann somit auf die Pointer verzichten. Ich denke das ist die sinnvollste und stabilste Variante.
Danke trotzdem an alle, die mitgeholfen haben
-
mhm, klappt doch nicht ganz ohne die pointer,
probiere schon eine Weile rum, aber komme nicht wirklich weiter mit dem unique_ptr...
typedef std::vector<std::unique_ptr<TElement>> pElementList; pElementList pElements; unique_ptr<TElement> pE(new TElement()); pE->InitElement(this,Template,left,top,4,4); pElements.push_back(pE);bei der letzten Zeile wirft mir der cimpiler eine 10-seitige Fehlermeldung um die Ohren aus der ich nicht wirklich was herausnehmen kann...
In file included from /usr/include/c++/4.4/i486-linux-gnu/bits/c++allocator.h:34,
from /usr/include/c++/4.4/bits/allocator.h:48,
from /usr/include/c++/4.4/string:43,
from /usr/include/c++/4.4/bits/locale_classes.h:42,
from /usr/include/c++/4.4/bits/ios_base.h:43,
from /usr/include/c++/4.4/ios:43,
from /usr/include/c++/4.4/ostream:40,
from /usr/include/c++/4.4/iostream:40,
from platine.h:1,
from platine.cpp:1:
/usr/include/c++/4.4/bits/unique_ptr.h: In member function ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = std::unique_ptr<TElement, std::default_delete<TElement> >]’:
/usr/include/c++/4.4/bits/stl_vector.h:737: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = std::unique_ptr<TElement, std::default_delete<TElement> >, _Alloc = std::allocator<std::unique_ptr<TElement, std::default_delete<TElement> > >]’
platine.cpp:499: instantiated from here
/usr/include/c++/4.4/bits/unique_ptr.h:214: error: deleted function ‘std::unique_ptr<_Tp, _Tp_Deleter>::unique_ptr(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = TElement, _Tp_Deleter = std::default_delete<TElement>]’
/usr/include/c++/4.4/ext/new_allocator.h:105: error: used here
In file included from /usr/include/c++/4.4/vector:69,
from platine.h:3,
from platine.cpp:1:
/usr/include/c++/4.4/bits/unique_ptr.h: In member function ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, _Args&& ...) [with _Args = const std::unique_ptr<TElement, std::default_delete<TElement> >&, _Tp = std::unique_ptr<TElement, std::default_delete<TElement> >, _Alloc = std::allocator<std::unique_ptr<TElement, std::default_delete<TElement> > >]’:
/usr/include/c++/4.4/bits/stl_vector.h:741: instantiated from ‘void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = std::unique_ptr<TElement, std::default_delete<TElement> >, _Alloc = std::allocator<std::unique_ptr<TElement, std::default_delete<TElement> > >]’
platine.cpp:499: instantiated from here
/usr/include/c++/4.4/bits/unique_ptr.h:214: error: deleted function ‘std::unique_ptr<_Tp, _Tp_Deleter>::unique_ptr(const std::unique_ptr<_Tp, _Tp_Deleter>&) [with _Tp = TElement, _Tp_Deleter = std::default_delete<TElement>]’
/usr/include/c++/4.4/bits/vector.tcc:314: error: used here
-
Es muss
pElements.push_back(std::move(pE));heißen. Dies hat auch Nexus falsch gemacht.
-
ok, danke
kann ich da nicht auf unique_ptr verzichten und std::move beim normalen vector anwenden (damit keine Kopie erstellt wird)?
TElement e; fElements.push_back(std::move(e));der compiler frisst es zumindest

-
Wenn der Default-Move-Ctor das richtige tut, oder du deinen eigenen hast, schon.
-
Was du auch noch machen könntest, wäre emplace_back zu verwenden. Dem übergibt man die Konstruktor-Argumente und das Element wird ohne Kopie direkt im vector erstellt.