Objekte werden zerstört

Hhm....damit ich richtig verstehe:

Der Standartkonstruktor darf also nicht in der cpp. Datei implementiert werden, da ich das schon in der .h Datei gemacht habe?
 
Hallo BLR

Das gilt für jede Funktion: Du darfst sie nur an einem Ort mit einen Funktionskörper versehen, entweder im Header oder in der cpp.

Viele Grüsse
Cromon
 
Die Funktion push_back erstellt eine Kopie von deinem übergebenen Objekt.

Du hast wahrscheinlich keinen Copy Operator definiert.
Normalerweise sollte dein Compiler bei dem Funktionsaufruf sofort meckern, aber anscheinend ruft deiner einfach den Standardkonstruktor, vermutlich Aufgrund der von Cromon genannten Tatsache der doppelten Konstruktordefinition, auf und du erhältst leere Objekte.

-> Wenn nicht nötig den einen Konstruktor entfernen.
-> Copy Operator für deine Klasse definieren.
 
Hallo veeman

Du hast recht, push_back erstellt eine Kopie. By default ist in C++ eine Kopie eines Objekts eine deep copy (im Gegensatz zu vielen anderen (Script-)Sprachen). Das heisst auch alle Member werden kopiert. Mit 'by default' meine ich, wenn kein Copy-Konstruktor definiert ist. Es gibt keinen Fehler, wenn du diesen nicht implementierst, die Standardvariante (wenn keine eigene definiert wurde) ist wohldefiniert.

Grundsätzlich muss ein copy-konstruktor nur im Rahmen der big-4 implementiert werden, also:
Wenn du einen der folgenden implementierst, implementiere alle:
1. Destruktor
2. Assignment-Operator
3. Copy-Constructor
4. Move-Constructor

Grüsse
Cromon
 
Die Funktion push_back erstellt eine Kopie von deinem übergebenen Objekt.
Soweit korrekt.

Du hast wahrscheinlich keinen Copy Operator definiert.
Es gibt in C++ keinen "Copy Operator". Meinst du den Copy-Konstruktor?

Normalerweise sollte dein Compiler bei dem Funktionsaufruf sofort meckern, aber anscheinend ruft deiner einfach den Standardkonstruktor, vermutlich Aufgrund der von Cromon genannten Tatsache der doppelten Konstruktordefinition, auf und du erhältst leere Objekte.
Wieso sollte der Compiler meckern? Ist kein Copy-Konstruktor deklariert, erzeugt der Compiler (in der Regel) automatisch einen Copy-Konstruktor.

BLR, ich habe deinen Code auf ein vollständiges Minimalbeispiel reduziert. Es funktioniert bei mir ohne den von dir beschriebenen Fehler.
C++:
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Liwanze {
public:
    enum Region { ndef=0, amer, apac, emea };
    
    Liwanze(const string& name, Region loc) : name(name), loc(loc) {
    }
    
    const string& get_name() const {
        return name;
    }
    
    Region get_loc() const {
        return loc;
    }
    
private:
    string name;
    Region loc;
};
 
void populate(vector<Liwanze> &li) {
    li.push_back(Liwanze("Sui", Liwanze::amer));
    li.push_back(Liwanze("Mark", Liwanze::amer));
    li.push_back(Liwanze("Robert", Liwanze::amer));
    li.push_back(Liwanze("Ralph", Liwanze::apac));
    li.push_back(Liwanze("Sven", Liwanze::amer)); 
}

int main() {
    vector<Liwanze> lvz;
    populate(lvz);
   
    for (int i = 0; i < lvz.size(); ++i) {
        cout << "Name: " << lvz.at(i).get_name()
             << " Region: " << lvz.at(i).get_loc() << endl;
    }
    
    return 0;
}

BLR, bitte erstelle ein vollständiges Minimalbeispiel, in dem das Problem auftritt. Und stelle bitte sicher, dass das Beispiel auch tatsächlich kompiliert. Sonst kommen wir hier nicht weiter.

Grüße
Matthias
 
Zuletzt bearbeitet:
By default ist in C++ eine Kopie eines Objekts eine deep copy (im Gegensatz zu vielen anderen (Script-)Sprachen). Das heisst auch alle Member werden kopiert.
Das kann man so allgemein nicht sagen. Sobald eine Klasse Zeiger oder Referenzen enthält, erzeugt der Default-Copy-Konstruktor nur eine flache Kopie.

Mit 'by default' meine ich, wenn kein Copy-Konstruktor definiert ist. Es gibt keinen Fehler, wenn du diesen nicht implementierst, die Standardvariante (wenn keine eigene definiert wurde) ist wohldefiniert.
Auch diese Aussage ist nicht allgemein gültig. Der Default-Copy-Konstruktor kann nicht immer automatisch generiert werden. Das ist zum Beispiel der Fall, wenn einer der Member nicht kopierbar ist.

Grundsätzlich muss ein copy-konstruktor nur im Rahmen der big-4 implementiert werden, also:
Wenn du einen der folgenden implementierst, implementiere alle:
1. Destruktor
2. Assignment-Operator
3. Copy-Constructor
4. Move-Constructor
Das scheint mir eine nicht ganz zu Ende gedachte Übertragung der "Rule of Three" von C++03 (Destruktor, Copy-Konstruktor und Copy-Assignment-Operator immer gemeinsam definieren) auf C++11 zu sein. Der Move-Konstruktor ist für die Korrektheit nicht nötig (kann aber bei der Effizienz helfen). Andererseits gibt es auch Fälle, in denen man einen Move-Konstruktor, aber keinen Copy-Konstruktor haben möchte/kann (z.B. std::unique_ptr). Siehe weiterführend dazu http://stackoverflow.com/a/4782927/764214.

Grüße
Matthias
 
Das kann man so allgemein nicht sagen. Sobald eine Klasse Zeiger oder Referenzen enthält, erzeugt der Default-Copy-Konstruktor nur eine flache Kopie.

Das klingt richtig, ist aber evtl. der Denkansatz, der in die falsche Richtung führt.

Der Zeiger ist nur ein Zeiger, und der wird sauber kopiert. Das, worauf er zeigt, natürlich nicht (ist ja auch nicht Bestandteil eines Pointers)

Referenzen werden gar nicht kopiert. Ein Objekt mit einer Referenz als Member ist nicht kopierbar.
 
Das kann man so allgemein nicht sagen. Sobald eine Klasse Zeiger oder Referenzen enthält, erzeugt der Default-Copy-Konstruktor nur eine flache Kopie.

Wie Endurion sagte ist das für mich so ein Grenzfall für die Klassifizierung. Wenn ich ein Objekt mit einem Zeiger kopiere ist für mich die Kopie der Adresse bereits eine deep copy, würde das Objekt worauf es zeigt kopiert hätte ja der Zeiger nacher auch einen anderen Wert, das entspricht für mich weniger einer Kopie sondern eher einer Art Reproduktion.

Das scheint mir eine nicht ganz zu Ende gedachte Übertragung der "Rule of Three" von C++03 (Destruktor, Copy-Konstruktor und Copy-Assignment-Operator immer gemeinsam definieren) auf C++11 zu sein. Der Move-Konstruktor ist für die Korrektheit nicht nötig (kann aber bei der Effizienz helfen). Andererseits gibt es auch Fälle, in denen man einen Move-Konstruktor, aber keinen Copy-Konstruktor haben möchte/kann (z.B. std::unique_ptr). Siehe weiterführend dazu http://stackoverflow.com/a/4782927/764214.

Das ist eine (bis auf den move-assignment-operator) zu Ende gedachte Übertragung der Rule of Three von C++03 auf C++11. Für mich gehört es zur Korrektheit dazu sich genau diese Gedanken zu machen. Das von dir angesprochene Beispiel sehe ich nicht als Widerspruch dazu sondern viel mehr als Bestätigung, siehe:
C++:
class Foo
{
public:
   virtual ~Foo();
   Foo(const Foo&) = delete;
   Foo(Foo&&);
   Foo& operator = (const Foo&);
};

std::unique_ptr ist bei mir auch so implementiert: unique_ptr(const _Myt&) = delete;

Wenn aber jemand findet, der move-Konstruktor kann nicht als Erweiterung der Serie gesehen werden kann ich das durchaus auch nachvollziehen, die ursprüngliche Regel ist ja auch nur da um zu verhindern, dass in den Fällen, in denen das nichtimplementieren des Copy-Konstruktors auch wirklich ein Problem birgt dies nicht passiert.

Viele Grüsse
Cromon
 
Zuletzt bearbeitet:
Hallo zusammen und noch mal vielen Dank für die Hilfe.
Der Fehler lag leider ganz wo anders. Ich hab es nicht wahrgenommen, weil ich nicht weiss, was es macht. Und zwar folgendes:

Die NetBeans -IDE hat mir in der Header-Datei folgendes erzeugt:

Code:
Liwanze(const Liwanze& orig);

und in der .cpp auch implementiert:

Code:
Liwanze::Liwanze(const Liwanze& orig) {
}

Also einen Konstruktor mit einer constanten Referenz auf die Klasse "Liwanze".
Aber was hat das für einen Sinn und warum hat es den Code so beeinflusst, dass ich
keine erzeugten Objekte mehr hatte****
 
Das klingt richtig, ist aber evtl. der Denkansatz, der in die falsche Richtung führt.

Der Zeiger ist nur ein Zeiger, und der wird sauber kopiert. Das, worauf er zeigt, natürlich nicht (ist ja auch nicht Bestandteil eines Pointers)
Wie Endurion sagte ist das für mich so ein Grenzfall für die Klassifizierung. Wenn ich ein Objekt mit einem Zeiger kopiere ist für mich die Kopie der Adresse bereits eine deep copy, würde das Objekt worauf es zeigt kopiert hätte ja der Zeiger nacher auch einen anderen Wert, das entspricht für mich weniger einer Kopie sondern eher einer Art Reproduktion.
Wenn also das reine Kopieren des Zeigers eine tiefe Kopie ist, was wäre dann eine flache Kopie? Kopie und Reproduktion sind für mich Synonym, daher verstehe ich nicht was du damit sagen willst.

Referenzen werden gar nicht kopiert. Ein Objekt mit einer Referenz als Member ist nicht kopierbar.
Wie kommst du denn darauf? Natürlich können solche Objekte kopiert werden.

Das ist eine (bis auf den move-assignment-operator) zu Ende gedachte Übertragung der Rule of Three von C++03 auf C++11. Für mich gehört es zur Korrektheit dazu sich genau diese Gedanken zu machen.
Klar sollte man sich überlegen, ob Move-Semantik für eine Klasse sinnvoll ist oder nicht. Aber sofern meine Klasse kopierbar ist, sollte die Existenz eines Move-Konstruktors keinen Einfluss darauf haben, ob sie korrekt funktioniert. Ich sehe es daher nicht so, dass man in diesem Fall unbedingt den Move-Konstruktor implementieren muss. Beim Beispiel mit unique_ptr wollte ich darauf hinaus, dass man in diesem Fall keinen Copy-Konstruktor implementieren kann. Wenn du = delete als Implementierung siehst (was ich auch nachvollziehen kann), ist das natürlich ein schlechtes Beispiel :) Abgesehen davon müsste man sich die Arbeit nicht machen, den Copy-Konstruktor und den Copy-Assignment-Operator explizit als gelöscht zu definieren, da das schon implizit geschieht, sofern ein Move-Konstruktor vom Benutzer definiert wurde.

Grüße
Matthias
 

Neue Beiträge

Zurück