Kann man so ein Objekt kopieren
-
Ich habe folgenden Code geschrieben
typedef boost::unordered_map<uint32_t, ddos_request, boost::hash<uint32_t> > map; map connections; boost::mutex mutex; //...D.h. die Map connection enthält also keine Pointer sondern Referenzen. Da mein Programm mehrere Threads verwendet muss diese Liste nun für Thread 2 kopiert werden, damit Thread 1 weiterarbeiten kann.
/* Kopiere die Connections map */ mutex.lock(); map connections_cp = connections; mutex.unlock(); // Lösche die Connnections map connections.clear();Ich frage mich jetzt ob connection_cp ein Kopie von connections ist (samt Inhalt) und damit völlig unabhängig von Veränderungen in connections ist?
-
Unter der Annahme, dass in dem Container Referenzen gespeichert sind und es sich um eine Multithread-Anwendung handelt, musst du den Zugriff bei jedem Zugriff auf eines der Elemente synchronisieren. Das ist auch dann noch notwendig, wenn du den Inhalt kopierst. Schließlich handelt es sich dann noch immer um Referenzen, die auch den anderen Threads zugänglich wären.
Eine Referenz ist letztendlich nur eine schönere Form eines Pointers.
In deinem Code löscht du zudem alle Einträge des Containers ohne diesen Zugriff zu synchroniseren.
-
Naja, Thread 2 arbeitet ja nur mit connections_cp und nicht mit connections. Nur Thread 1 benutzt connections, nicht Thread 2. Und der Kopiervorgang ist geschützt.
Ich versuche meine Frage nochmal anders zu formulieren. Ich habe in connections Objekte gespeichert und keine Pointer. Z.B. so
Object obj; //erstelle ein Object
connections[21] = obj;Jetzt wird obj an eine Stelle in der Map kopiert, d.h. es gibt zwei unabhängige Objekt nämlich obj und connections[21]. Verändere ich nun obj irgendwie, dann ist connections[21] davon nicht betroffen.
Wenn ich aber jetzt die Map kopiere,
map connections_cp = connections;
dann, dann sind die Objekte an connections_cp[21] und connections[21] doch vollkommen unabhängig von einander, d.h. Veränderungen an connections[21] wirken sich in keinster Weise auf connections_cp[21] aus.
Das stimmt doch, oder?
-
Kommst du zufällig aus der Java-Ecke? Du würfelst die Begriffe Referenz und Objekt nämlich ein wenig durcheinander.
Hier zum Beispiel:
typedef boost::unordered_map<uint32_t, ddos_request> map;erstellt durchaus (solange ddos_request kein typedef für eine Referenz ist) eine Map mit Objekten dieses Typs, und nicht mit Referenzen auf ddos_requests.
Und das:
HändyÄndy schrieb:
Jetzt wird obj an eine Stelle in der Map kopiert, d.h. es gibt zwei unabhängige Objekt nämlich obj und connections[21]. Verändere ich nun obj irgendwie, dann ist connections[21] davon nicht betroffen.
ist so auch nicht koscher, wenn du in connections wirklich Referenzen speicherst.
Wenn es dir um wirkliche Referenzen geht: Wenn du eine Map aus Referenzen auf Objekte kopierst, werden sich in der neuen Map nur Kopien der Referenzen befinden. Diese Referenzen referenzieren dann immer noch die ursprünglichen Objekte (wo auch immer du diese erstellst).
Ansonsten wäre es gut zu wissen, was genau du jetzt in deiner Map speichern willst.
-
Ja, ich komme tatsächlich aus der Java Ecke.
ddos_request ist eine Klasse, daher bekomme ich durch
ddos_request r;
ja eine Instanz oder ein Objekt diesen Typs, also keine Referenz. Dieses Objekt speicher ich dann in der map zB mittels
connections[21] = r;
D.h. ja, dass connections[21] dann eine Kopie des Objekts r ist bzw. ich denke doch mal das connections[21] dann wenigstens eine Referenz auf eine Kopie des Objekts r ist?
Wenn ich nun die map connections kopieren möchte, d.h. die Objekte aus connections mitkopieren möchte, dann kann ich das doch hoffentlich so machen:
map connections_cp = connections;
Oder gehe ich falsch inder Annahme?
-
Es tatsächlich so wie ich es vermutet habe. Hier ein Beispielprogramm
#include <string> #include <iostream> #include <boost/unordered_map.hpp> using std::cout; using std::endl; using std::string; class packet { public: std::string name; int num; packet(); //packet( const packet& ); packet( std::string name, int num ); }; packet::packet() { cout << "Leerer Konstruktor" << endl; }; /* packet::packet( const packet& p ) { cout << "Copy Konstruktor für " << p.name << endl; num = p.num; name = p.name; };*/ packet::packet( std::string name_, int num_ ) { cout << "Standard Konstruktor" << endl; name = name_; num = num_; } typedef boost::unordered_map<int, packet, boost::hash<int> > map; map connections; map connections_cp; int main( int argc, const char* argv[] ) { connections[1] = packet( "Eins", 1); connections[2] = packet( "Zwei", 2); cout << "connections[1].name = " << connections[1].name << " connections[1].num = " << connections[1].num << endl; cout << "connections[2].name = " << connections[2].name << " connections[2].num = " << connections[2].num << endl; cout << "Vor dem Kopiervorgang" << endl; connections_cp = connections; cout << "Nach dem Kopiervorgang" << endl; connections.clear(); cout << "connections[1].name = " << connections[1].name << " connections[1].num = " << connections[1].num << endl; cout << "connections[2].name = " << connections[2].name << " connections[2].num = " << connections[2].num << endl; cout << "connections_cp[1].name = " << connections_cp[1].name << " connections_cp[1].num = " << connections_cp[1].num << endl; cout << "connections_cp[2].name = " << connections_cp[2].name << " connections_cp[2].num = " << connections_cp[2].num << endl; }Ausgabe auf der Konsole:
[anthovak@findthee test]$ ./runme
Standard Konstruktor
Leerer Konstruktor
Standard Konstruktor
Leerer Konstruktor
connections[1].name = Eins connections[1].num = 1
connections[2].name = Zwei connections[2].num = 2
Vor dem Kopiervorgang
Nach dem Kopiervorgang
Leerer Konstruktor
connections[1].name = connections[1].num = 6507264
Leerer Konstruktor
connections[2].name = connections[2].num = 6507264
connections_cp[1].name = Eins connections_cp[1].num = 1
connections_cp[2].name = Zwei connections_cp[2].num = 2Also passiert genau das, was ich vermutet habe.
Die Objekte in connections werden nach connections_cp kopiert und damit sind beide maps unabhängig voneinander.