Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Kopierkonstruktor vs. expliziter Standard-Zuweisungsoperator

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 < [ 2 ]
000
09.08.2006, 11:31 Uhr
Yadgar



High!

Was ich mich im Augenblick frage: wozu wird eigentlich bei Klassenobjekten, die keinen Speicher (oder sonstige Ressourcen, wobei ich mir bei meinem gegenwärtigen Kenntnisstand unter "Ressourcen" nur dynamischen Speicher wirklich vorstellen kann) dynamisch zugewiesen bekommen, zwischen Kopierkonstruktor und (explizitem Standard-)Zuweisungsoperator unterschieden? Hinsichtlich der Anwendung sind doch beide identisch - oder täusche ich mich da?

Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
09.08.2006, 13:00 Uhr
ao

(Operator)



Zitat von Yadgar:
... wobei ich mir bei meinem gegenwärtigen Kenntnisstand unter "Ressourcen" nur dynamischen Speicher wirklich vorstellen kann ...

Als Resource gilt alles, was man sich verschafft und solange belegt hält, wie man es braucht. Wenn eine Klasse z.B. ein File öffnet und offenhält, ist das File eine Resource, die richtig kopiert werden muss. Ähnlich verhält es sich mit TCP-Verbindungen, Audio-Geräten, Registry-Schlüsseln und so weiter. Vereinfach gesagt mit allem, was eine Open-Close-Mimik hat und bei dem das Open fehlschlagen kann.

Zitat:
zwischen Kopierkonstruktor und (explizitem Standard-)Zuweisungsoperator unterschieden? Hinsichtlich der Anwendung sind doch beide identisch ...

Nicht ganz.

C++:
MyClass mc (otherClass); // Copy-Ctor
mc = yetAnotherClass; // operator=

 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
09.08.2006, 13:11 Uhr
Yadgar



High!

(wo ist hier der Smily für *anKopfklatsch*?)

Natürlich, der Kopierkonstruktor initialisiert, während der Zuweisungsoperator von einem schon initialisierten Objekt ausgeht!

Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
09.08.2006, 13:31 Uhr
0xdeadbeef
Gott
(Operator)


Ich benutz dafür immer

Wie dem auch sei, einen interessanten Fall gibt es noch, und zwar

C++:
MyClass mc;
MyClass mc2 = mc;


In diesem Fall wird der Copy-Konstruktor benutzt. = bei der Initialisierung ist nur eine verschönende Schreibweise für Konstruktoren mit einem Parameter.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
12.08.2007, 18:56 Uhr
_Daniel_



hallo, ich hätte da ne frage bezüglich den kopierkonstruktoren

ich hab schon von vielen gehört, dass man einen kopierkonstruktor benötigt um eine tiefe kopie zu erzeugen, ich hab selber ein wenig herumprobiert und auf folgendes gestoßen, dass man auch ne tiefe kopie ohne kopierkonstruktor erzeugen kann nämlich:


C++:
//**********************
//********_DB_**********
//**********************

#include <stdio.h>
#include <iostream>

class Katze
{
      public:
             int getAge() const;
             void setAge(int weight);
             Katze();
             //Katze (const Katze &);
             //Katze(int weight);
      //private:
              int itsweight_;
      };
      
Katze::Katze()
{
              
}


/*
Katze::Katze(const Katze &Ricki)
{
    itsweight_ = 9;
                   }
*/


void Katze::setAge(int weight)
{
    itsweight_ = weight;
}

int Katze::getAge() const
{
    return (itsweight_);
}


int main()
{
    Katze Puma;
    Puma.setAge(5);
    std::cout << "Katze Puma wiegt: " << Puma.getAge() << std::endl;
    int *ptr = &Puma.itsweight_;
    std::cout << "Katze Puma ptr: " << ptr << std::endl;
    
    Katze Fridolin;
    //int *Fridolin = &Puma;
    std::cout << "\nKatze Fridolin wiegt: " << Fridolin.getAge() << std::endl;
    Fridolin.setAge(6);
    std::cout << "Katze Fridolin wiegt: " << Fridolin.getAge() << std::endl;
    std::cout << "Katze Puma wiegt: " << Puma.getAge() << std::endl;
    
    Katze Ricky(Puma);
    std::cout << "\nKatze Ricky wiegt: " << Ricky.getAge() << std::endl;
    std::cout << "Katze Puma wiegt: " << Puma.getAge() << std::endl;
    ptr = &Ricky.itsweight_;
    std::cout << "Katze Ricky ptr: " << ptr << std::endl;
    Ricky.setAge(8);
    std::cout << "Katze Ricky wiegt: " << Ricky.itsweight_ << std::endl;
    
    std::cout << "Katze Puma wiegt: " << Puma.itsweight_ << std::endl;
    
    Katze *Moritz = &Puma;
    std::cout << "Katze Moritz wiegt: " << Moritz->getAge() << std::endl;
    Moritz->setAge(10);
    std::cout << "Katze Moritz wiegt: " << Moritz->getAge() << std::endl;
    std::cout << "Katze Puma wiegt: " << Puma.getAge() << std::endl;
//HIER WIRD NE FLACHE KOPIE ERSTELLT    

    Katze Mor(Puma);
    std::cout << "Katze Mor wiegt: " << Mor.getAge() << std::endl;
    Mor.setAge(15);
    std::cout << "Katze Mor wiegt: " << Mor.getAge() << std::endl;
    std::cout << "Katze Puma wiegt: " << Puma.getAge() << std::endl;
    Puma.setAge(20);
    std::cout << "Katze Puma wiegt: " << Puma.getAge() << std::endl;
    std::cout << "Katze Mor wiegt: " << Mor.getAge() << std::endl;
    getchar();  
}



ich weiß den unterschied zwischen flacher und tiefer kopie nur in einem coding fällt es mir dann schwer es zu bestimmen! kann mir da jemand helfen?

thx im voraus

ps: hat es mit pointern zu tun, das ich wegen diesen, weil die ja dann auch das gleiche objekt zeigen und darum man einen kopierkonstrukor benötigt?

Dieser Post wurde am 12.08.2007 um 22:24 Uhr von FloSoft editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
12.08.2007, 20:05 Uhr
Kest
saint


Hi!

Jetzt nicht als Beleidigung gemeint, aber wie's aussieht, verstehste das doch nicht richtig.

Naja, bei deinem Beispiel wird 'ne Deep Copy auch nie benötigt: du belegst ja gar keine Resourcen. Und das von wegen >ne tiefe kopie ohne kopierkonstruktor< (ich bin davon ausgegangen, dass du damit das hier >Katze *Moritz = &Puma;< gemeint hast) hat mit Copy-Konstruktoren nichts zu tun: >Moritz< ist 'n Zeiger und du lässt ihn auf ein anderes Objekt zeigen.

Default-Copy-Konstruktoren führen immer Shallow Copy durch, weswegen man auch einen nicht zu definieren braucht, wenn es keine Resourcen belegt werden (ist auch viel schneller). Aber genau deswegen besteht die Möglichkeit selbst einen zu entwerfen, der Deep Copy benutzt.

Was man bei dem ganzen Mist zu verstehen braucht: wenn man eine Resource belegt, dann sollte man einen eigenen Copy-Konstruktor erstellen, der die Resource richtig kopiert, sonst wird die gleiche Resource auch von anderen Objekten benuzt.

Als Beispiel kannste dir jede billige String-Implementierung ansehen.

Oder so was als 'n Beispiel für typische vernunftwidrige Klassen:

C++:
class A
{
      public:
             A(int a){ current=new int(a); }
             A(const A& a){ current=new int(*a.current); }
                  
             int get() const{ return *current; }
             void set(int a){ *current=a; }
              
      private:
              int* current;
};

int main()
{
    A a(1);
    A b(a);
    a.set(45);
    std::cout << a.get() << '\t' << b.get();
}

--
Wenn man einen Hufschlag hört, sollte man >Pferd< denken und nicht >Zebra<.

Dieser Post wurde am 12.08.2007 um 20:18 Uhr von Kest editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
12.08.2007, 20:37 Uhr
_Daniel_



ich hatte mir eben gedacht nachdem die ausgaben wie folgt aussieht ... :

Katze Puma wiegt: 5
Katze Puma ptr: 0x22ff70

Katze Fridolin wiegt: 5
Katze Fridolin wiegt: 6
Katze Puma wiegt: 5

Katze Ricky wiegt: 5
Katze Puma wiegt: 5
Katze Ricky ptr: 0x22ff64
Katze Ricky wiegt: 8
Katze Puma wiegt: 5

Katze Moritz wiegt: 5
Katze Moritz wiegt: 10
Katze Puma wiegt: 10
Katze Moritz wiegt: 55
Katze Puma wiegt: 55

Katze Mor wiegt: 55
Katze Mor wiegt: 15
Katze Puma wiegt: 55
Katze Puma wiegt: 20
Katze Mor wiegt: 15

da nichts verändert wurde an den ergebnissen und werten von Katze Ricky(Puma);
und es heißt doch immer, wenn die werte nicht verändert werden, dann hat man eine DEEP COPY erstellt, mhhhh?

Katze Ricky wiegt: 5
Katze Puma wiegt: 5
Katze Ricky ptr: 0x22ff64
Katze Ricky wiegt: 8
Katze Puma wiegt: 5

ich hab hinterher immer geschaut ob sich der wert von Puma verändert hat, und darum dachte ich mir, weil er immer gleich geblieben ist, dass es eine DEEP KOPY ist.

> < (ich bin davon ausgegangen, dass du damit das hier >Katze *Moritz = &Puma;< gemeint
> hast) hat mit Copy-Konstruktoren nichts zu tun: >Moritz<

nein, das hatte ich mir als FLACHE KOPIE vorgestellt, aber als flache kopie wird ja die initialisierung wert1=wert2 geschrieben oder, weil bei pointern ist es doch klar, dass sich die werte verändern.

ich dachte mir auch, dass wenn ich pointer habe, desshalb keine flache kopie gemacht gehört?!?

meintest du mit ressource, etwas aufn heap zu kopieren?

dank für die schnelle antwort, will einfach net so wirklich "klar" werden!
hoffe noch auf nützliche antworten und das doch ein wenig besser zu verstehen
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
12.08.2007, 22:08 Uhr
Kest
saint



Zitat von _Daniel_:
und es heißt doch immer, wenn die werte nicht verändert werden, dann hat man eine DEEP COPY erstellt, mhhhh?


Hab so was nie gehört.

Bei >Katze *Moritz = &Puma;< wird überhaupt nichts kopiert, sonders deferenziert. D.h. nicht >FLACHE KOPIE<, sondern gar keine.


Zitat von _Daniel_:

meintest du mit ressource, etwas aufn heap zu kopieren?


ja, auch das.

Also wenn man oben bei meinem Beispiel >A(const A& a){ current=new int(*a.current); }
< wegmacht, wird immer Shallow Copy durchgeführt. Mach mal, dann siehste was passiert. So aber wird Deep Copy durchgeführt.

>Shallow Copy< und >Deep Copy< sollte man nur im Zusammenhang mit Resourcen benutzen, bzw. sie unterscheiden. Bei dir

C++:
class Katze
{
public:
int getAge() const;
void setAge(int weight);
Katze();
//Katze (const Katze &;
//Katze(int weight);
//private:
int itsweight_;
};


sind keine Resourcen drin, also brauchste dir gar keine Gedanken darüber zu machen wie und was...
--
Wenn man einen Hufschlag hört, sollte man >Pferd< denken und nicht >Zebra<.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
12.08.2007, 22:25 Uhr
0xdeadbeef
Gott
(Operator)


Flache Kopie bedeutet, dass das Objekt einfach stumpf binär kopiert wird. Alle Werte bleiben gleich, es werden keine Änderungen an anderen Stellen im Programm vorgenommen. Wenn irgendetwas als Referenz gehalten wird - also Zeiger auf Heap-Objekte, Dateibezeichner oder vergleichbare Dinge, geht sowas gerne schief. Zum Beispiel:

C++:
class A {
public:
  A(int x) { p = new int(x); }
  ~A() { delete p; }

  int get_value() const throw() { return *p; }
private:
  int *p;
};

// ...

{
  A a1 = 4;
  A *a2 = new A(a1);
} // a1 wird hier zerstört, a1.p also auch
int x = a2->get_value(); // FEHLER!


In solchen Fällen muss dann eine Tiefenkopie gemacht werden, die eine Kopie des referenzierten Wertes anlegt und in der Kopie die referenziert.
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
12.08.2007, 22:29 Uhr
Kest
saint


Ich glaub, man kann >a2< nicht benutzen, weil der ja nicht in demselben Gültigkeitsbereich liegt?
--
Wenn man einen Hufschlag hört, sollte man >Pferd< denken und nicht >Zebra<.

Dieser Post wurde am 12.08.2007 um 22:30 Uhr von Kest editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 < [ 2 ]     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: