Dynamisches Pointerarray kopieren



  • Hi,

    ich möchte ein dynamisches Array komplett kopieren, d.h. mitsamt allen verwendeten Pointern.

    Ist mein Vorgehen prinzipiell richtig? Ich habe da ein wenig Bauchschmerzen bei dem Mischen von new und memcpy.

    Bekomme ich eigentlich irgendwie heraus, wie lang mein Array ist, wenn ich die 3 nicht wie in meinem Beispiel als Variable mitschleppe?
    Hab es schon mit verschiedenen sizeof's probiert, aber was verwertbares war nicht dabei. 😕

    Achso, Vektoren kann ich nicht verwenden, da mir auf der Zielmaschine die STL fehlt...

    Gruß, Thomas

    // Die Klasse, dessen Objekte in einer Liste gespeichert werden soll
    	class Person {
    	public:
    		char* name;
    		int alter;
    	};
    
        // Eine Liste erstellen
        int length = 3;
    	Person** liste = new Person*[length];
    
    	liste[0] = new Person;
    	liste[0]->name = "John";
    	liste[0]->alter = 42;
    	liste[1] = new Person;
    	liste[1]->name = "Bob";
    	liste[1]->alter = 30;
    	liste[2] = new Person;
    	liste[2]->name = "Lucy";
    	liste[2]->alter = 32;
    
        // Die Liste kopieren
    
    	Person** copy = new Person*[length];
    	memcpy(copy, liste, length * sizeof(class Person*));
    	for (int i = 0; i < length; i++) {
    		copy[i] = new Person;
    		memcpy(copy[i], liste[i], sizeof(class Person));
    	};
    
        // Objekte löschen
        delete[] liste;
        delete[] copy;
    


  • Hallo

    nein das ist nicht korrekt. Zum einen kopierst du zuerst das ganze Array, und danach noch mal jedes Element des Arrays selbst, was doppelt gemoppelt ist. Und dann wird bei dem Member name auch nur die Adresse kopiert, nicht aber der Inhalt. Das bedeutet das sowohl Original als auch Kopie für den Member name auf denselben Speicher zeigen.

    Das ganze kannst du dir auch einfach ersparen, indem du die Mittel des C++ Standard benutzt

    #include <string>
    #include <vector>
    
    ...
      class Person {
        public:
            std::string name;
            int alter;
        };
    ...
    std::vector<Person> Orignal;
    ... // Original füllen
    std::vector<Person> Kopie = Orignal; // komplettes Kopieren
    

    Zum Umgang mit vector und string siehe die C++FAQ, das Magazin und diverse Turorials.

    bis bald
    akari



  • Zum einen kopierst du zuerst das ganze Array,

    Ja, dann hab ich die erste "Pointerebene" abgehandelt, die Memberpointer zeigen immer noch auf die Member des Originals.

    und danach noch mal jedes Element des Arrays selbst, was doppelt gemoppelt ist.

    Ja, denn erst dann sind meine kopierten Member eigenständig.

    Und dann wird bei dem Member name auch nur die Adresse kopiert, nicht aber der Inhalt. Das bedeutet das sowohl Original als auch Kopie für den Member name auf denselben Speicher zeigen.

    Hm, bei meinen Tests konnte ich den Original-Member ändern, ohne dass sich die Kopie geändert hat. 😕

    Das ganze kannst du dir auch einfach ersparen, indem du die Mittel des C++ Standard benutzt

    Wie gesagt, ich hab keine STL, ergo keine Vektoren oder Strings.

    std::vector<Person> Kopie = Orignal; // komplettes Kopieren
    

    Hab's grad mal auf dem PC ausprobiert, das scheint mir keine echten Kopien der Daten zu liefern. 😕

    Gruß, Thomas



  • Hallo

    Ja, denn erst dann sind meine kopierten Member eigenständig.

    Nein, es werden die Member kopiert. Bei einem Pointer wird die Adresse kopiert, nicht aber die Instanz, die zu dieser Adresse gehört.

    Hab's grad mal auf dem PC ausprobiert, das scheint mir keine echten Kopien der Daten zu liefern

    Doch in meinem Beispiel wird alles korrekt kopiert. Woran willst du merken, das keine echte Kopie erstellt wird?

    Wie gesagt, ich hab keine STL, ergo keine Vektoren oder Strings.

    Das muß ich irgendwie überlesen haben. Wobei ich mir die Frage stelle, wieso die STl fehlen soll, wenn du doch mit new etwas aus dem C++ Standard nimmst? Das wird so auch nicht unter C laufen.

    Wenn du also reines C erstellen willt, dann las dich ins Ansi-C Forum verschieben.
    Auch jedenfall must du, wenn du wirklich unabhängige Kopieen haben willst, nicht nur die Person-Instanzen selber kopieren, sondern auch das auf was die Member name verweisen.

    bis bald
    akari



  • Das memcpy ausserhalb der Schleife macht shallow-copy, und danach folgt die Schleife die deep-copy macht (wenn auch nicht vollständig "deep", weil bei den strings ja bloss die pointer kopiert werden), womit das erste memcpy komplett hinfällig wird.

    Weiters solltest du für PODs die du noch dazu mit memcpy rumkopierst zumindest des guten Stil wegens "struct" statt "class" verwenden und auf jegliche access specifier verzichten.

    WasissnPOD: http://www.parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.7

    Ich bin mir auch nicht ganz sicher ob ein POD mehrere "public:" enthalten darf... an anderen Stellen hat ein "public:" zwischen 2 Member-Deklarationen nämlich durchaus nicht zu unterschätzende Auswirkungen, auch wenn ALLE Member public sind. Da aber sowieso alles public sein muss würde ich eben wie vorgeschlagen einfach struct nehmen und die "public" weglassen, dann bist du was das angeht auf der sicheren Seite.

    UDTs die keine PODs sind darfst du in C++ nämlich schonmal garnicht mit memcpy kopieren. Es geht oft genug trotzdem, aber damit verlässt du dich dann halt auf undefined behaviour Dingsbumbs.

    Und wenn am Zielsystem du keine STL hast, dann schreib dir entweder minimale Klassen für string, vector etc. selbst (müssen ja nicht so toll und vollständig wie die der STL sein), oder, besser, verwende irgendeine Lib/ein Framework welches ohne STL auskommt, auf dem Zielsystem läuft und diese einfachen Klassen zur Verfügung stellt.

    BTW: um was für ein Zielsystem handelt es sich? Vielleicht kann dir dann ja jmd. einen Tip geben...


Anmelden zum Antworten