Wo wird hier der Kopierkonstruktor aufgerufen??



  • Hallo!

    Ich habe folgende Klasse geschrieben:

    class Set
    {

    int Size;
    Lnode *pstart;

    public:
    Set();
    Set(int val);
    ~Set();
    Set(const Set& m);

    int size();

    int insert(int val);
    int remove(int val);
    int empty();
    bool element(int val) const;
    void print() const;
    Set &operator=(const Set &menge);

    friend Set operator+(const Set &menge1, const Set &menge2);
    friend Set operator*(const Set &menge1, const Set &menge2);
    friend bool operator<=(const Set &menge1, const Set &menge2);
    friend bool operator==(const Set &menge1, const Set &menge2);
    };

    Nun defeniere ich in einem Testprogramm:
    Set menge1, menge2, menge3;

    Wenn ich jetzt
    "menge3 = menge1 + menge2;"
    code, wird der Kopierkonstruktor aufgerufen (und erzeugt nen Fehler!).
    Warum??
    Ich glaubte der Kopierkostr. wird nur bei Initialisierungen mit einem anderen Objekt aufgerufen!?

    Soll ich noch anderen Funktionen herherkopieren, die wichtig sein könnten?

    Danke an alle 😉



  • Original erstellt von cbk18:
    **Ich glaubte der Kopierkostr. wird nur bei Initialisierungen mit einem anderen Objekt aufgerufen!?
    **

    Nein, umgekehrt. In der Regel macht man das so in der Art.

    Set& Set::operator=(const Set& set) {
      m_sonstwas1 = set.m_sonstwas1;
      m_sonstwas2 = set.m_sonstwas2;
      return *this;
    }
    
    Set::Set(const Set& set) {
      *this = set;
    }
    

    Original erstellt von cbk18:
    **Soll ich noch anderen Funktionen herherkopieren, die wichtig sein könnten?
    **

    Das wär nett...



  • In der Zeile

    menge3 = menge1 + menge2;
    

    Wird der =-Operator und der +-Operator aufgerufen. Vielleicht verwendet einer der Beiden intern den copy-C'tor



  • Original erstellt von Helium:
    Vielleicht verwendet einer der Beiden intern den copy-C'tor

    In dem o.g. Code würde es aber auf den Ersten Blick keinen Sinn machen...



  • Wo in dem Code sollte denn sonst eine Copy-C'tor aufgerufen werden:

    Set menge1, menge2, menge3;
    menge3 = menge1 + menge2;
    

    Du übersiehst außerdem den Pointer in der Klasse. Das heißt er wird wohl neuen Speicher alokieren müssen (Nicht i +, aber im Gleich). Und da wird auf jedenfall eine Copy-C'tor fällig.



  • Original erstellt von Helium:
    Wo in dem Code sollte denn sonst eine Copy-C'tor aufgerufen werden:

    Ich habe nur gesagt, dass man im + bzw. = operator in der Regel keinen Copy-Constructor (der eigenen Klasse) braucht.

    Original erstellt von Helium:
    Du übersiehst außerdem den Pointer in der Klasse. Das heißt er wird wohl neuen Speicher alokieren müssen (Nicht i +, aber im Gleich). Und da wird auf jedenfall eine Copy-C'tor fällig.

    Der Pointer ist aber vom Typ Lnode. Beim alloziieren wird kein Copy-Konstruktor aufgerufen, nur beim initialisieren.



  • Nein, umgekehrt. In der Regel macht man das so in der Art.

    Set& Set::operator=(const Set& set) {
    m_sonstwas1 = set.m_sonstwas1;
    m_sonstwas2 = set.m_sonstwas2;
    return *this;
    }

    Set::Set(const Set& set) {
    *this = set;
    }

    Nein so macht man das in der Regel (oder im Allgemeinen) nicht.
    Ein Zuweisung ist etwas anderes als eine Konstruktion.

    Was man hingegen häufig macht ist den copy-assignment Operator über den Copy-Konstruktor zu implementieren:

    class Foo
    {
    public:
        Foo(const Foo& rhs);
        void swap(const Foo&) /* throw() */;
        Foo& operator=(const Foo& rhs)
        {
             Foo temp(rhs);
             swap(temp);
             return *this;
        }
    };
    

    Wo in dem Code sollte denn sonst eine Copy-C'tor aufgerufen werden:

    Set menge1, menge2, menge3;
    menge3 = menge1 + menge2;

    Ganz einfach:

    Set operator+(const Set &menge1, const Set &menge2);
    

    Der operator+ liefert ein Set-Objekt by value. Und was bedeutet value-Return doch noch gleich? Richtig. Der Copy-Ctor der Klasse *muss* aufrufbar sein, da ein value-Return konzeptionell *immer* über den Copy-Ctor geschieht.
    Würde dort:

    Set menge3 = menge1 + menge2;
    

    dann könnte das Ergebnis der Addition direkt in den Speicher von menge3 konstruiert werden (RVO). Es würde wohl kein Copy-Ctor aufgerufen werden. Trotzdem muss er aufrufbar sein.

    Da wir in diesem Fall aber eine Zuweisung und keine Initialisierung haben, fällt die Möglichkeit für eine in-place-construction flach.
    Das temporäre Ergebnis-Objekt der Addition wird per Copy-Ctor-Aufruf erzeugt.

    [ Dieser Beitrag wurde am 02.06.2003 um 12:15 Uhr von HumeSikkins editiert. ]

    [ Dieser Beitrag wurde am 02.06.2003 um 12:16 Uhr von HumeSikkins editiert. ]



  • Also erstmal vielen Dank für die vielen Zuschriften!

    Ich kopiere mal zunächst die beiden Funktionen hier rein:

    Vorweg vielleicht noch eins: Der Code ist sicherlich nicht so optimal, ich stecke noch in den Kinderschuhen, was C++ angeht. Aber darum bin ich ja hier! 😉

    Set operator+(const Set &menge1, const Set &menge2)
    {
        Set unionSet;
    
        Lnode *pnode = menge1.pstart;
    
        while (pnode)
        {
            unionSet.insert(pnode->val);
            pnode = pnode->next;
        }
    
        /* Menge 2 in neue Liste kopieren */
        /* Die Funktion insertSetElement kuemmert sich um doppelte Elemente */
        pnode = menge2.pstart;
    
        while (pnode)
        {
            unionSet.insert(pnode->val);
            pnode = pnode->next;
        }
    
        return unionSet;
    }
    

    und

    Set &Set::operator=(const Set &menge)
    {
        if (&menge != this)
        {
    
            Lnode *pnode = menge.pstart;
    
            empty();
    
            while (pnode)
            {
                insert(pnode->val);
                pnode = pnode->next;
            }
        }
        return *this;
    }
    

    Übrigens: Kann mir bitte einer sagen, wie ich den Text in C++ -Stil hier aussehen lassen kann? Hab das nicht hinbekommen! Hab das markiert und dann unten auf den C++ Button gedrückt, hat aber nicht funktioniert.

    Aber ich glaube ich habe das jetzt verstanden!
    In der operator+ Funktion wird ein "Objekt" geschaffen und mittels Copy-C'tor an den (diese Funktion) aufrufenden Teil zurück"kopiert". Oder?

    BK
    Bitte Code-Tags verwenden!

    [ Dieser Beitrag wurde am 02.06.2003 um 12:58 Uhr von HumeSikkins editiert. ]



  • Ähm, der rote Smiley war keine Absicht!
    Wie kann ich das editieren?
    Danke.



  • Original erstellt von HumeSikkins:
    **Nein so macht man das in der Regel (oder im Allgemeinen) nicht.
    Ein Zuweisung ist etwas anderes als eine Konstruktion.

    Was man hingegen häufig macht ist den copy-assignment Operator über den Copy-Konstruktor zu implementieren:

    class Foo
    {
    public:
        Foo(const Foo& rhs);
        void swap(const Foo&) /* throw() */;
        Foo& operator=(const Foo& rhs)
        {
             Foo temp(rhs);
             swap(temp);
             return *this;
        }
    };
    

    **

    Und wo liegen bei deiner Variante die Vorteile??? Es ist doch eigentlich das selbe nur mit einem temporären Objekt... 😕



  • Original erstellt von MaSTaH:
    Und wo liegen bei deiner Variante die Vorteile??? Es ist doch eigentlich das selbe nur mit einem temporären Objekt... 😕

    es werden keine default ctoren aufgerufen.

    stell dir mal vor die klasse beinhaltet ein objekt als member.

    bei deiner version wäre es das selbe wie wenn man

    Klasse obj;
    obj=foo;

    schreiben würde, bei Hume ist
    Klasse obj(foo);
    effizienter als
    Klasse obj;
    obj=foo;



  • Es ist doch eigentlich das selbe

    Nö. In deinem Fall werden beim Copy-Ctor erstmal alle Member-Objekte per Default-Ctor und PODs überhaupt nicht initialisiert.
    Das ist häufig schonmal ein Performance-Nachteil (Default-Initialisierung + Assignment statt einfach einmal Initialisierung mit dem richtigen Wert) und einen viel schöneren Nachteil der daraus resultiert findest du hier erklärt:
    http://www.c-view.org/tech/pattern/cpptips/cpyctor_assign



  • Original erstellt von Shade Of Mine:
    es werden keine default ctoren aufgerufen.

    Ich stehe jetzt auf dem Schlauch. Wo werden bei mir denn Default-C'tors aufgerufen?



  • Original erstellt von HumeSikkins:
    In deinem Fall werden beim Copy-Ctor erstmal alle Member-Objekte per Default-Ctor und PODs überhaupt nicht initialisiert.

    Ups, jetzt wo du es sagst... 🙄 🙂



  • Ganz einfach:

    Set operator+(const Set &menge1, const Set &menge2);

    *Vor den Kopf schlag*


Anmelden zum Antworten