vector hinzufügen ohne objekt zu kopieren (ggf. refcount++)
-
Hallo,
nachdem der unique_ptr für TElement super funktioniert, wollte ich das ganze auch für die unterklasse TConnection machen...kann mir mal jemand verraten, wie man aus diesem Kauderwelsch etwas entnehmen kann?
$ g++ -Wall -std=c++0x platine.cpp -o platine `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0` In file included from /usr/include/c++/4.4/vector:64, from platine.h:3, from platine.cpp:13: /usr/include/c++/4.4/bits/unique_ptr.h: In static member function ‘static _ForwardIterator std::__uninitialized_copy<<anonymous> >::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<TConnection, std::default_delete<TConnection> >*, std::vector<std::unique_ptr<TConnection, std::default_delete<TConnection> >, std::allocator<std::unique_ptr<TConnection, std::default_delete<TConnection> > > > >, _ForwardIterator = std::unique_ptr<TConnection, std::default_delete<TConnection> >*, bool <anonymous> = false]’: /usr/include/c++/4.4/bits/stl_uninitialized.h:117: instantiated from ‘_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<TConnection, std::default_delete<TConnection> >*, std::vector<std::unique_ptr<TConnection, std::default_delete<TConnection> >, std::allocator<std::unique_ptr<TConnection, std::default_delete<TConnection> > > > >, _ForwardIterator = std::unique_ptr<TConnection, std::default_delete<TConnection> >*]’ /usr/include/c++/4.4/bits/stl_uninitialized.h:257: instantiated from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, std::allocator<_Tp>&) [with _InputIterator = __gnu_cxx::__normal_iterator<const std::unique_ptr<TConnection, std::default_delete<TConnection> >*, std::vector<std::unique_ptr<TConnection, std::default_delete<TConnection> >, std::allocator<std::unique_ptr<TConnection, std::default_delete<TConnection> > > > >, _ForwardIterator = std::unique_ptr<TConnection, std::default_delete<TConnection> >*, _Tp = std::unique_ptr<TConnection, std::default_delete<TConnection> >]’ /usr/include/c++/4.4/bits/stl_vector.h:243: instantiated from ‘std::vector<_Tp, _Alloc>::vector(const std::vector<_Tp, _Alloc>&) [with _Tp = std::unique_ptr<TConnection, std::default_delete<TConnection> >, _Alloc = std::allocator<std::unique_ptr<TConnection, std::default_delete<TConnection> > >]’ platine.h:199: 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 = TConnection, _Tp_Deleter = std::default_delete<TConnection>]’ /usr/include/c++/4.4/bits/stl_uninitialized.h:74: error: used hereclass TConnection { ... public: TConnection(TPlatine *board,TElement *elmt,int ID,string name); //inside TElement //TConnection(TPlatine *board,int x,int y,string name); //outside TElement virtual ~TConnection() {}; ... } typedef std::vector<std::unique_ptr<TConnection>> pConnectionList; class TElement { ... public: ... pConnectionList pConnections;der Fehler kommt erst wenn ich das pConnections-Feld in TElement einbaue. bei der reinen typedef nicht. Dachte erst, es liegt an meinen 2 Ctoren, aber der Fehler kommt auch nur mit einem...
ich habe im code noch nichts, wo ich auf pConnections zugreife (bzw. auskommentiert).
-
Dasselbe wie vorhin, du versuchst irgendwo einen unique_ptr zu kopieren.
-
eben nicht, wenn ich die Zeile im TElement auskommentiere wird fehlerfrei compiliert...ich verwende also nirgendwo das pConnections. somit wird davon auch kein Element kopiert
die ganzen Zugriffe habe ich schon auskommentiert zur Fehlereingrenzung
-
platine.h Zeile 199.
-
Wenn Du welche Zeile auskommentierst?
Die Fehlermeldungen sehen so aus, als ob an irgendeiner Stelle versucht würde, ein vector von uninque_ptr-Objekten zu kopieren, möglicherweise auch indirekt (z.B. in einem vom Compiler generierten copy-ctor für TEelement), den du versehentlich irgendwo verwendest.
Genug geraten.
-
mhm, wenn ich eine pConnectionList in TPlatine definiere (wo die pElementList drin ist) kommen keine Fehler...kommt der fehler evtl. durch die Struktur, dass ich eine Liste von Elementen habe die selbst eine Liste mit connections haben?
class TConnection {...}; typedef std::vector<std::unique_ptr<TConnection>> pConnectionList; class TElement { ... public //pConnectionList pConnections; //funktioniert nicht }; typedef std::vector<std::unique_ptr<TElement>> pElementList; class TPlatine { ... private pElementList pElements; //funktioniert pConnectionList pConnections; //funktioniert };was mir grade auffällt...in TElement ist die Liste public, in TPlatine private...hat das vielleicht damit was zu tun?
den public zugriff bräuchte ich aber (sonst müsste ich mit zugriffsroutinen schreiben)
Zeile 199 wäre nur die einleitende Klammer von TElement...trotz pConnectionList im private von TElement kommt der Fehler.
TElement erzeuge ich nur über TPlatine::AddElement, welche so aussieht:
void TPlatine::AddElement(std::string Template,int left,int top) { int width=4; std::unique_ptr<TElement> pE(new TElement(this,Template,left,top,width,4)); pElements.push_back(std::move(pE)); }ansonsten hat nur TConnection noch ein feld, welches so definiert ist und zugewiesen wird:
TElement *fElement; TConnection::TConnection(TPlatine *board,TElement *elmt,int ID,string name) { fElement=elmt; }
-
Zeig doch mal bitte den Code um Zeile 199 her, so kommen wir nicht weiter...
-
class TElement { //Zeile 199, fehler kommt aktuell auch noch in der Zeile (platine.h:199: instantiated from here) private: int fLeft,fTop,fWidth,fHeight; std::string fTemplate,fPrefix; //int fNumber; std::string fValue;//,fUnit; int fDirection; TPlatine *fPlatine; pConnectionList pConnections; protected:habe den aktuellen code mal hier hochgeladen: http://dl.dropbox.com/u/3228629/platine.zip
-
Aus Spass kannst du bei TElement ja mal einen privaten undefinierten Copy-Ctor hinzufügen; denn kopierbar ist das Ding nicht (wegen des pConnection-Vektors) und so kann ein solcher Fehler früher abgefangen werden. Das fliegt Dir dann nicht erst irgendwo im Code von vector<unique_ptr> um die Ohren.
-
meinst du einen leeren copy-constructor?
also so:
class TElement { private: ... TElement(const TElement& e) {}; // copy constructorda bekomme ich nen Fehler
platine.h: In member function ‘bool TPlatine::OnRedraw(GdkEventExpose*)’:
platine.h:210: error: ‘TElement::TElement(const TElement&)’ is private
platine.cpp:555: error: within this context
platine.cpp:555: error: initializing argument 1 of ‘void TPlatine::DrawElement(TElement)’zeile 210 ist die definition des copy-CTors siehe oben
evtl ist in Zeile 555 schon der Hund begraben...
hier der code-Ausschnitt:
for (unsigned int i=0; i<pElements.size();i++) { DrawElement(*pElements[i]); //zeile 555 }
-
Nein. Nicht leer. Sonder einfach gar nicht definieren.
class TElement { private: TElement(const TElement& e); ...frank schrieb:
da bekomme ich nen Fehler
platine.h: In member function ‘bool TPlatine::OnRedraw(GdkEventExpose*)’:
platine.h:210: error: ‘TElement::TElement(const TElement&)’ is private
platine.cpp:555: error: within this context
platine.cpp:555: error: initializing argument 1 of ‘void TPlatine::DrawElement(TElement)’zeile 210 ist die definition des copy-CTors siehe oben
Wie ich vermutet habe, wird versucht, ein TElement-Objekt zu kopieren. Wenn so ein Objekt aber einen unkopierbaren vector enthält (weil er zB unique_ptr-Objekte speichert), dann geht das natürlich nicht.
frank schrieb:
evtl ist in Zeile 555 schon der Hund begraben...
hier der code-Ausschnitt:
for (unsigned int i=0; i<pElements.size();i++) { DrawElement(*pElements[i]); //zeile 555 }Anhand der Fehlermeldung kann ich entnehmen, dass Du DrawElement so deklariert hast:
void DrawElement(TElement);und die hätte vielleicht so aussehen sollen:
void DrawElement(TElement const&);
-
Habe das soweit eingebaut
void DrawElement(TElement const &e);platine.cpp: In member function ‘void TPlatine::DrawElement(const TElement&)’:
platine.cpp:259: error: passing ‘const TElement’ as ‘this’ argument of ‘TRect TElement::GetRect()’ discards qualifiers259: TRect r=e.GetRect();GetRect ist eine public-methode, welche interne variablen zurückgibt...sollte imho mit const-pointer auch funktionieren
wenn ich das const in DrawElement weglasse, kommt kein Fehler. Weis nur nicht, ob das so sein soll
durch das & wird jedoch das TElement nicht kopiert, sondern nur der pointer der Funktion übergeben, aus meiner Sicht richtig
-
ich habe die pConnectionList wieder eingebaut und bisher funktioniert alles (also es compiliert
)...herzlichen Dank an alle, die mir geholfen haben
-
frank schrieb:
GetRect ist eine public-methode, welche interne variablen zurückgibt...sollte imho mit const-pointer auch funktionieren
Sollte. Dazu musst du die Funktion aber auch bei der Deklaration entsprechend markieren mit einem const. Beispiel:
class A { int z; public: A() : z(0) {} void dings() {++z;} int bums() [b]const[/b] {return z;} };frank schrieb:
wenn ich das const in DrawElement weglasse, kommt kein Fehler. Weis nur nicht, ob das so sein soll

Nein. Das war die falsche Stelle.
frank schrieb:
durch das & wird jedoch das TElement nicht kopiert, sondern nur der pointer der Funktion übergeben, aus meiner Sicht richtig
so ähnlich.
Du schreibst einfach so C++ Code hin, ohne zu wissen, was er genau bedeutet? Mit der Strategie fällst Du sehr schnell auf die Klappe bei C++. Dir fehlt da so einiges an Grundlage. Schaff Dir mal ein schlaues Buch an und lerne...
-
krümelkacker schrieb:
Sollte. Dazu musst du die Funktion aber auch bei der Deklaration entsprechend markieren mit einem const. Beispiel:
class A { int z; public: A() : z(0) {} void dings() {++z;} int bums() [b]const[/b] {return z;} };wenn ich die funktion als const definiere, kann darin nichts verändert werden. bei der GetRect muss es auch nicht, aber irgendwann brauche ich auch den schreibenden Zugriff auf Elemente des übergebenen Objektes.
was ist denn so schlimm, wenn ich das const weglasse? die referenz selbst kann ich doch nicht ändern, sondern nur das Objekt dahinter...und das will ich ja
krümelkacker schrieb:
so ähnlich.
Du schreibst einfach so C++ Code hin, ohne zu wissen, was er genau bedeutet? Mit der Strategie fällst Du sehr schnell auf die Klappe bei C++. Dir fehlt da so einiges an Grundlage. Schaff Dir mal ein schlaues Buch an und lerne...
habe hier das "Einstieg in c++" von arnold willemer. das lese ich nebenbei durch.
mit dieser ganzen Pointergeschichte begehe ich nur Neuland, welches unter c++ komplizierter ist als in anderen Programmiersprachen (wie aus meinem Komplett-Code ersichtlich ist, versuche ich ein Delphi-Programm zu portieren)ok, Zeiger und Referenz sind unter c++ etwas anderes und doch fast gleich, das ist mir entfallen und beim const kommt es auch darauf an, wo es genau steht.
-
frank schrieb:
wenn ich die funktion als const definiere, kann darin nichts verändert werden.
Es würde auch keiner erwarten, dass eine Funktion namens "DrawElement" das übergebene Objekt modifiziert. Um genau das auszudrücken, wird const verwendet.
frank schrieb:
bei der GetRect muss es auch nicht, aber irgendwann brauche ich auch den schreibenden Zugriff auf Elemente des übergebenen Objektes.
bei "DrawElement" ?!
frank schrieb:
was ist denn so schlimm, wenn ich das const weglasse?
Wenn Du es bei GetRect weglässt, kannst Du GetRect nur auf einem Objekt aufrufen, wenn Du auch "Schreibzugriff" auf das Objekt hast. Aber warum solltest Du Schreibzugriff haben müssen, nur um das Objekt nach etwas fragen zu können?
frank schrieb:
die referenz selbst kann ich doch nicht ändern, sondern nur das Objekt dahinter...und das will ich ja
Wo?
-
krümelkacker schrieb:
frank schrieb:
was ist denn so schlimm, wenn ich das const weglasse?
Wenn Du es bei GetRect weglässt, kannst Du GetRect nur auf einem Objekt aufrufen, wenn Du auch "Schreibzugriff" auf das Objekt hast. Aber warum solltest Du Schreibzugriff haben müssen, nur um das Objekt nach etwas fragen zu können?
ich meinte eigentlich das const beim DrawElement

krümelkacker schrieb:
frank schrieb:
die referenz selbst kann ich doch nicht ändern, sondern nur das Objekt dahinter...und das will ich ja
Wo?
bisher noch nicht, da ich noch keine Setter-Methoden groß drin habe...
Aber meine Befürchtung ist, dass ich irgendwann eine solche Methode habe, wo ich schreibzugriff habe (und brauche) und dann eine solche const-funktion aufrufen muss...
wenn ich da keine Probleme (lässt sich evtl. nur mit const-element aufrufen) bekomme ists ok
nochmals danke, dass du dir so viel Zeit für meine Probleme nimmst...allein auf die Idee mit dem Copy-Constructor zur Fehlersuche wäre ich nicht gekommen.
-
eine Frage dazu hätte ich noch...
wie sähe eine Getter-Methode für die unique_ptr<TElement> aus?
unique_ptr<TElement> GetElement(/*std::string name*/ int index) const {return pElements[index];};und
TElement& GetElement(/*std::string name*/ int index) const {return pElements[index];};funktionieren nicht...
-
Bevor du einfach irgendwas ausprobierst, mach dich mit der Materie vertraut. Schau dir das Konzept von Zeigern genau an (z.B. wann du Dereferenzierung brauchst). Anschliessend schaust du dir die Semantik von
unique_ptran und merkst, dass der Besitz transferiert wird, es also relativ sinnfrei ist, eineconst-Methode einenunique_ptrzurückgeben zu lassen.
-
ok, da ich weder unique_ptr zurückgeben noch TElement kopieren kann, habe ich es mal so probiert:
TElement& GetElement(/*std::string name*/ int index) const {return *pElements[index];};funktioniert auch mit folgendem Code:
TElement &e=platine.GetElement(idx); e.Rotate(false);müsste doch stimmen, oder?
habt ihr eine gute (möglichst deutsche) dokumentation zu unique_ptr? was ich so über google gefunden habe, war nicht wirklich verständlich für mich. mein Buch behandelt die STL nur rudimentär und die Smart-Pointer (unique_ptr/shared_ptr/auto_ptr) gar nicht.