Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.

copy konstruktor

[es] :: C/C++ programiranje :: copy konstruktor

Strane: 1 2

[ Pregleda: 7738 | Odgovora: 22 ] > FB > Twit

Postavi temu Odgovori

Autor

Pretraga teme: Traži
Markiranje Štampanje RSS

Pretender

Član broj: 12407
Poruke: 100
212.124.182.*



Profil

icon copy konstruktor23.09.2003. u 01:30 - pre 233 meseci
Code:
1:     // Listing 10.11
2:     // Returning the dereferenced this pointer
3:
4:     typedef unsigned short  USHORT;
5:     #include <iostream.h>
6:
7:     class Counter
8:     {
9:        public:
10:          Counter();
11:          ~Counter(){}
12:          USHORT GetItsVal()const { return itsVal; }
13:          void SetItsVal(USHORT x) {itsVal = x; }
14:          void Increment() { ++itsVal; }
15:          const Counter& operator++ ();
16:
17:       private:
18:          USHORT itsVal;
19:
20:    };
21:
22:    Counter::Counter():
23:    itsVal(0)
24:    {};
25:
26:    const Counter& Counter::operator++()
27:    {
28:       ++itsVal;
29:       return *this;
30:    }
31:
32:    int main()
33:    {
34:       Counter i;
35:       cout << "The value of i is " << i.GetItsVal() << endl;
36:       i.Increment();
37:       cout << "The value of i is " << i.GetItsVal() << endl;
38:       ++i;
39:       cout << "The value of i is " << i.GetItsVal() << endl;
40:       Counter a = ++i;
41:       cout << "The value of a: " << a.GetItsVal();
42:       cout << " and i: " << i.GetItsVal() << endl;
48:     return 0;
49: }

Output: The value of i is 0
The value of i is 1
The value of i is 2
The value of a: 3 and i: 3


Citat:
As discussed above, if the Counter object allocated memory, it would be important to override the copy constructor. In this case, the default copy constructor works fine.

Molim Vas, kada se to ovde poziva default copy konstruktor, kada se objekat predaje po referenci ?


Hvala
 
Odgovor na temu

Dragi Tata
Malo ispod Kanade

Član broj: 1958
Poruke: 3906
..ndg-pm4-2.dialup.nethere.net



+6 Profil

icon Re: copy konstruktor23.09.2003. u 02:12 - pre 233 meseci
Ovde:

Code:
Counter a = ++i;


Copy konstruktor i inače uzima konstantnu referencu kao argument.
 
Odgovor na temu

Pretender

Član broj: 12407
Poruke: 100
212.124.182.*



Profil

icon Re: copy konstruktor23.09.2003. u 17:17 - pre 233 meseci
Moram da priznam da sam sad malo zbunjen.

Znam da Copy konstruktor uzima konstantnu referencu kao argument, ali zasto ga ovde uopste pozivamo, kada je prethodno dat primer:
Code:
58:    // functionTwo, passes a const pointer
59:    const SimpleCat * const FunctionTwo (const SimpleCat * const theCat)
60:    {
61:             cout << "Function Two. Returning...\n";
62:             cout << "Frisky is now " << theCat->GetAge();
63:             cout << " years old \n";
64:             // theCat->SetAge(8);   const!
65:             return theCat;

ovde se predaje pokazivac, ali isto je i sa referencom; uzeo sam bas ovaj prim. jer je upravo ispod njega komentar:
Citat:
The constructor, copy constructor, and destructor are still defined to print their messages. The copy constructor is never called, however, because the object is passed by reference and so no copies are made.


Sve u svemu, ovaj C++ je uzasno komplikovaniji od COBOL-a, uh...
 
Odgovor na temu

Dragi Tata
Malo ispod Kanade

Član broj: 1958
Poruke: 3906
199.171.112.*



+6 Profil

icon Re: copy konstruktor23.09.2003. u 17:31 - pre 233 meseci
Ova dva primera nemaju veze jedan sa drugim. Ako funkciji proslediš referencu, neće da se pozove copy konstruktor, jer se objekat uopšte ne kopira. Mešutim, ako pogledaš liniju

Code:

Counter a = ++i;


ovaj izraz bi odgovarao sledećem izrazu koji bi objekat a napravio na heap-u umesto na steku:

Code:

Counter* a = new Counter(++i);


Kapiraš? Ovde si napravio nov objekat tipa Counter (a) i inicijalizovao si ga tako što si iskopirao vrednost objekta i (posle ++ operacije) pa sad imaš dva različita objekta. Znači, ovde dolazi do kopiranja, a kod prosleđivanja reference kao parametra funkcije ne dolazi do kopiranja. Tu je razlika.
 
Odgovor na temu

Pretender

Član broj: 12407
Poruke: 100
212.124.182.*



Profil

icon Re: copy konstruktor23.09.2003. u 18:23 - pre 233 meseci
AVE CEZARE

Da vidimo, samo, da li sam razumeo ono sa redefinisanjem copy konstruktora u slucaju:
Citat:
Code:

Counter* a = new Counter(++i);


trebalo bi napraviti copy konstr.(umesto default-a):
Code:
 // redefinisani copy konstruktor

Counter::Counter(const Counter & rhs)
{
    itsVal = new int;
    *itsVal = rhs.GetItsVal();
}
    


da bi se dobila tzv. duboka kopija.

?
 
Odgovor na temu

Dragi Tata
Malo ispod Kanade

Član broj: 1958
Poruke: 3906
199.171.112.*



+6 Profil

icon Re: copy konstruktor23.09.2003. u 23:25 - pre 233 meseci
Jok, vala. To ne može ni da se kompajlira (itsVal nije pointer). Isti copy konstruktor služi u oba slučaja - taman posla kad bi to zavisilo od načina na koji korisnik klase instancira objekte.
 
Odgovor na temu

Pretender

Član broj: 12407
Poruke: 100
*.beotel.net



Profil

icon Re: copy konstruktor24.09.2003. u 03:41 - pre 233 meseci
Da, ja sam koristio primer jedne klase, koja ima clanove pokazivace(sad vidim):
Code:
1:   // Listing 10.5
2:   // Copy constructors
3:
4:   #include <iostream.h>
5:
6:   class CAT
7:   {
8:       public:
9:            CAT();                         // default constructor
10:            CAT (const CAT &);     // copy constructor
11:            ~CAT();                         // destructor
12:            int GetAge() const { return *itsAge; }
13:            int GetWeight() const { return *itsWeight; }
14:            void SetAge(int age) { *itsAge = age; }
15:
16:       private:
17:            int *itsAge;
18:            int *itsWeight;
19:  };
20:
21:  CAT::CAT()
22:  {
23:       itsAge = new int;
24:       itsWeight = new int;
25:       *itsAge = 5;
26:       *itsWeight = 9;
27:  }
28:
29:  CAT::CAT(const CAT & rhs)
30:  {
31:       itsAge = new int;
32:       itsWeight = new int;
33:       *itsAge = rhs.GetAge();
34:       *itsWeight = rhs.GetWeight();
35:  }
36:
37:  CAT::~CAT()
38:  {
39:       delete itsAge;
40:       itsAge = 0;
41:       delete itsWeight;
42:       itsWeight = 0;
43:  }
44:
45:  int main()
46:  {
47:       CAT frisky;
48:       cout << "frisky's age: " << frisky.GetAge() << endl;
49:       cout << "Setting frisky to 6...\n";
50:       frisky.SetAge(6);
51:       cout << "Creating boots from frisky\n";
52:       CAT boots(frisky);
53:       cout << "frisky's age: " <<     frisky.GetAge() << endl;
54:       cout << "boots' age: " << boots.GetAge() << endl;
55:       cout << "setting frisky to 7...\n";
56:       frisky.SetAge(7);
57:       cout << "frisky's age: " <<     frisky.GetAge() << endl;
58:       cout << "boot's age: " << boots.GetAge() << endl;
59:     return 0;
60: }

Jesse kaze da bi default copy konstr. napravio `plitku` kopiju (tj. clanovi 2 klase pokazivali bi na istu lokaciju, sto je opasno), i zato pravimo sopstveni copy kon. /ovde mi nije bas jasno zasto bi, prema datoj slici, default copy k. pravio kopiju na Free Store umesto na steku? ali dobro/

Kako dakle da uspostavim analogiju sa primerom klase Counter, tj. kako bih u ovom primeru uradio ono sto kaze autor:
Citat:
As discussed above, if the Counter object allocated memory, it would be important to override the copy constructor.

mada eto, kazes da isti copy k. sluzi u oba slucaja, i ja sam se sada opet zapetljao >=<@
Ili bi mozda bilo bolje da prosto preskocim ove kucine?
 
Odgovor na temu

Rapaic Rajko
Bgd

Član broj: 4105
Poruke: 805
*.pexim.co.yu



+62 Profil

icon Re: copy konstruktor24.09.2003. u 08:51 - pre 233 meseci
E bre, uspori malo.
Nije tako strasno kao sto izgleda. Baci pogled na ove dve linije:
Code:

  Counter a = ++i;
  Counter &a = ++i;


U cemu je razlika?
Prva linija. Redosled je sledeci:
1) prvo se izvrsava operator ++ objekta 'i' koji vraca referencu na 'i';
2) zatim se zbog operatora dodeljivanja '=' poziva copy constructor, jer se objektu 'a' dodeljuje 'by value' rezultat operatora ++. Prosledjivanje 'by value' znaci kopiranje podatka (u ovom slucaju objekta), otuda i naziv 'copy constructor'.

Druga linija. NE poziva se copy constructor, jer se REFERENCI 'a' dodeljuje 'by reference' rezultat operatora ++. Posto operator ++ inace vraca referencu (return *this), prosto se referenca dodeli referenci i to je to.

E sad, u drugom slucaju, reference 'a' i 'i' gadjaju isti objekat, to jest bitno je izmenjen smisao prvobitnog koda; cilj je bio da ti pojasnim stvar.
Pozdrav

Rajko
 
Odgovor na temu

Pretender

Član broj: 12407
Poruke: 100
*.beotel.net



Profil

icon Re: copy konstruktor24.09.2003. u 16:03 - pre 233 meseci
Hvala, to je bilo vrlo helpful, ali jos uvek ne znam kako da realizujem ovo:
Citat:
The implementation of operator++, on lines 26-30, has been changed to dereference the this pointer and to return the current object. This provides a Counter object to be assigned to a. As discussed above, if the Counter object allocated memory, it would be important to override the copy constructor. In this case, the default copy constructor works fine.
 
Odgovor na temu

Rapaic Rajko
Bgd

Član broj: 4105
Poruke: 805
*.pexim.co.yu



+62 Profil

icon Re: copy konstruktor25.09.2003. u 10:21 - pre 233 meseci
Idemo redom:

1) TVOJ copy constructor bi bio sasvim ok, da nisi napravio jedan previd. Zbunio si se, jer si poredio kod klase Counter i klase Cat. U klasi Counter field itsVal je tipa "int" (NE pointer, NE referenca), a u klasi Cat field-ovi itsAge i itsWeight su tipa "int*" (pointer na integer). Sad ti je jasno: pointeru moras da kreiras objekat na koji gadja sa new(). Prema tome, posto u klasi Counter NEMAMO pointere, sledi:
Code:

Counter::Counter(const Counter & rhs)
{
  itsVal = rhs.GetItsVal();
}


2) Zasto se preporucuje da se napravi sopstveni copy constructor? Zato sto C++ obezbedjuje default copy constructor, koji radi najjednostavnije moguce: sve field-ove prosto prekopira. Zamisli to u slucaju da su field-ovi pointeri na neku memoriju; imao bi dva ili vise objekta ciji field-ovi "share-uju" istu memoriju. Iz tog razloga, OBAVEZNA je praksa da se pravi sopstveni copy constructor.

Rajko

P.S. Verujem da gornji constructor moze jos krace da se napise (koriscenjem dvotacke) ali da ti ne komplikujem pricu...
P.P.S. Dobro, u klasi Counter nije tip field-a int vec USHORT, ali verujem da si shvatio sustinu; ionako su to sve ordinalni tipovi.
 
Odgovor na temu

Pretender

Član broj: 12407
Poruke: 100
*.beotel.net



Profil

icon Re: copy konstruktor26.09.2003. u 01:32 - pre 233 meseci
Hvala Rajko. Ovo je sad skoro potpuno shvaceno.
Evo zasto `skoro`:

Autor je za primer `izrade` copy konstr. uzeo klasu koja ima clanove pokazivace (class Cat), a tu je i najociglednije kako taj c.c. stvarno alocira novu mem. za novi objekat, sa new.
I sam autor kaze:
Citat:
Typically there'd be little reason for a class to store int member variables as pointers, but this was done to illustrate how to manage member variables on the free store.

Izvor zabune je u stvari bio taj, sto nije prikazano kako se pravi novi c.c. kada su clanovi obicni.

E sad, kada`smo`to resili, the final question is:

Kako se iz ovog koda:
Citat:
Code:

Counter::Counter(const Counter & rhs)
{
  itsVal = rhs.GetItsVal();
}

vidi da c.c. alocira novu mem.(upravo sam zato i napravio onu gresku u c.c.- povuklo me je ono new), jer ja iz datog koda citam samo da se pravi kopija i dodeljuje polju ItsVal.
Znaci sta ovde govori da se radi o `dubokoj` kopiji, a ne o `plitkoj`, koju bi napravio default c.c.?

Imam neki osecaj, da je moje pitanje mozda trivijalno, ali uz sav rizik, molim za odgovor.


Hvala

P.S. Inace tacka (2) je OK.
P.P.S. Zasto mi se lomi kod u citatima?

 
Odgovor na temu

Rapaic Rajko
Bgd

Član broj: 4105
Poruke: 805
*.pexim.co.yu



+62 Profil

icon Re: copy konstruktor26.09.2003. u 13:20 - pre 233 meseci
E, tu smo.
Sledi malo koda:
Code:

  class AnyClass 
  {
    private:
      char aChar;
      char *paChar;
      short aShort;
      short *paShort;
      AnyOtherClass aObject;
      AnyOtherClass *paObject;
      ....
  }


Sad ce ti sve postati kristalno jasno. Idemo field po field, i posmatramo sta i kako compiler (constructor) radi sa njima, to jest koliko im memorije dodeljuje:
Code:

  char aChar;             // constructor dodeljuje 1 bajt 
  char *paChar;          // constructor dodeljuje 4 bajta (velicina pointera je 4 bajta)
  short aShort;           // constructor dodeljuje 2 bajta (je l' bese toliko?)
  short *paShort;        // constructor dodeljuje 4 bajta (opet pointer)
  AnyOtherClass aObject;     // ? bajtova (velicina instance klase AnyOtherClass)
  AnyOtherClass *paObject; // opet 4 bajta (pointer, nego sta)


Treba li jos nesto da dodam?
A da, field AnyOtherClass aObject...sta radi compiler u njegovom slucaju? Instancira ga tako sto poziva njegov DEFAULT constructor koji odradi isto sto i mi u gornjem primeru: skenira field po field i dodeljuje memoriju najbolje sto ume -) .
To bi bilo to.

Rajko
 
Odgovor na temu

Pretender

Član broj: 12407
Poruke: 100
*.beotel.net



Profil

icon Re: copy konstruktor27.09.2003. u 01:20 - pre 233 meseci
Sve to jeste kristalno jasno.

Da li bih ja mogao da zakljucim sledece:

1) Kada su clanovi klase obicne promenljive (ne pokazivaci) - nema razlike izmedju plitke i duboke kopije (nas c.c. ce raditi isto sto i default c.c.)- jer onda, valjda, nema mogucnosti da polja razlicitih objekata dele istu lokaciju; ili mozda gresim?
Jer, one korake, koje si u gornjoj analizi naveo, obavlja i default c.c.. isto kao sto bi i nas?

2) Kada u klasi imamo pokazivace, moramo da napravimo poseban c.c. i u njemu dodelimo pokazivacima nove lokacije sa new.(inace ce polja razlicitih objekata pokazivati na istu lokaciju)


Je li to mozda to ?

p.s. U knjizi je uopste slabo objasnjena organizacija memorije.(znam filmile..)
 
Odgovor na temu

Dragi Tata
Malo ispod Kanade

Član broj: 1958
Poruke: 3906
..ndg-pm4-2.dialup.nethere.net



+6 Profil

icon Re: copy konstruktor27.09.2003. u 05:27 - pre 233 meseci
U principu si u pravu. Jedino bih dodao da u slučaju kad imamo pokazivače, neki put želimo da pokazuju na iste objekte, tako da ono "mora" zvuči malo prejako.
 
Odgovor na temu

Pretender

Član broj: 12407
Poruke: 100
*.beotel.net



Profil

icon Re: copy konstruktor27.09.2003. u 20:55 - pre 233 meseci
Hvala DT-u i Rajku. All clear.
 
Odgovor na temu

Pretender

Član broj: 12407
Poruke: 100
*.beotel.net



Profil

icon Re: copy konstruktor27.09.2003. u 21:28 - pre 233 meseci
Da ne otvaram novu temu, molio bih 1 proveru.

U obradi operatora dodele, autor kaze:
Citat:
There is an added wrinkle with the assignment operator, however. The object catTwo already exists and has memory already allocated. That memory must be deleted if there is to be no memory leak.

Code:
30: CAT CAT::operator=(const CAT & rhs)
31: {
32:    if (this == &rhs)
33:       return *this;
34:    delete itsAge;
35:    delete itsWeight;
36:    itsAge = new int;
37:    itsWeight = new int;
38:    *itsAge = rhs.GetAge();
39:    *itsWeight = rhs.GetWeight();
40:    return *this;
41: }

Medjutim, u jednom zadatku, on koristi sledeci kod:

Code:
SimpleCircle& SimpleCircle::operator=(const SimpleCircle & rhs)
{
     if (this == &rhs)
          return *this;
     *itsRadius = rhs.GetRadius();
     return *this;
}

cime, ne samo sto ostavlja memorijsku pukotinu (jer ne brise mem.), nego, cini mi se, pravi i `plitku` kopiju (jer sada 2 pokazivaca gadjaju istu lokaciju, obzirom da GetRadius() vraca pokazivac.(?)

Hvala

p.s. ..da ne pominjem da je u ovom zadatku na 3 mesta greskom (ne stamparskom-poredio sam sa e-verzijom), inkrementirao adresu umesto pokazivaca. (vec imam solidan index gresaka, koji cu na kraju ovde postovati, kako bih eventualno pomogao sapatnicima)

 
Odgovor na temu

Dragi Tata
Malo ispod Kanade

Član broj: 1958
Poruke: 3906
..ndg-pm4-2.dialup.nethere.net



+6 Profil

icon Re: copy konstruktor29.09.2003. u 00:34 - pre 233 meseci
Oba primera su ispravna, mada su odrađena na različiti način. U prvom je uništio stare objekte (sa delete), pa kreirao nove (sa new), a u drugom je jednostavno postojećoj memorijskoj lokaciji dodelio novu vrednost. Drugi način je očigledno jednostavniji, ali nije uvek moguć. Doduše, u CAT primeru je ladno mogao da postupi na isti način, ali je verovatno hteo da ilustruje kako se pravi copy konstruktor "u opštem slučaju".
 
Odgovor na temu

Pretender

Član broj: 12407
Poruke: 100
*.beotel.net



Profil

icon Re: copy konstruktor29.09.2003. u 21:27 - pre 233 meseci
Da da. Ja sam ovde malo pobrkao operator dodele sa copy konstruktorom.
 
Odgovor na temu

Rapaic Rajko
Bgd

Član broj: 4105
Poruke: 805
*.pexim.co.yu



+62 Profil

icon Re: copy konstruktor30.09.2003. u 09:18 - pre 233 meseci
Pretender:
Da ne otvaram novu temu, molio bih 1 proveru.

U obradi operatora dodele, autor kaze:
Citat:
There is an added wrinkle with the assignment operator, however. The object catTwo already exists and has memory already allocated. That memory must be deleted if there is to be no memory leak.

Code:
30: CAT CAT::operator=(const CAT & rhs)
31: {
32:    if (this == &rhs)
33:       return *this;
34:    delete itsAge;
35:    delete itsWeight;
36:    itsAge = new int;
37:    itsWeight = new int;
38:    *itsAge = rhs.GetAge();
39:    *itsWeight = rhs.GetWeight();
40:    return *this;
41: }

[/quote]

Majko mila, koja ti je to knjiga? Ona izjava gore (na engleskom) je NEBULOZNA. Kakav crni memory leak...Gledaj ovako: za pointere itsAge i itsWeight ti vec imas dodeljenu memoriju. Tu memoriju citas i u nju upisujes tako sto radis dereferenciranje pointera (*itsAge i *itsWeight); sto se tebe tice, ta memorija JESTE najprostiji integer, i tako joj dodeljujes vrednost. Prema tome, u gornjem primeru je potpuno NEPOTREBNO unistavanje te memorije i ponovno kreiranje (linije 34-37); jednostavno dodelis vrednosti i to je to (linije 38 i 39).

Citat:

Medjutim, u jednom zadatku, on koristi sledeci kod:

Code:
SimpleCircle& SimpleCircle::operator=(const SimpleCircle & rhs)
{
     if (this == &rhs)
          return *this;
     *itsRadius = rhs.GetRadius();
     return *this;
}

cime, ne samo sto ostavlja memorijsku pukotinu (jer ne brise mem.), nego, cini mi se, pravi i `plitku` kopiju (jer sada 2 pokazivaca gadjaju istu lokaciju, obzirom da GetRadius() vraca pokazivac.(?)


NEMOGUCE da GetRadius vraca pointer; pogledaj jos jednom. Ako je, recimo, deklaracija sledeca: "float *itsRadius", onda izraz (*itsRadius) dereferencira memoriju tipa float, sto znaci da funkcija GetRadius vraca isto (return *itsRadius). Proveri.
Pozdrav

Rajko

 
Odgovor na temu

Pretender

Član broj: 12407
Poruke: 100
*.beotel.net



Profil

icon Re: copy konstruktor02.10.2003. u 13:26 - pre 233 meseci
Izvinjavam se zbog kasnjenja.

Sto se tice onog memory leaka, kad bolje pogledam, stvarno ne znam gde autor to vidi(knjiga je legendarna: C++ za 21 day).

I za ono 2. si u pravu:

Code:
int SimpleCircle::GetRadius() const
{
     return *itsRadius;
}


..nije lako usvojiti tu pokazivacku logiku.


A, kad smo vec kod toga, imam neke nedoumice u vezi sa pokazivacima na stringove.

1)
char *pok = "aj sad";
cout << pok << "\n";

izlaz: aj sad

U radu sa pointerom na integer, dobili bi iz cout<<pok, adresu pokazivane lokacije, pa sam ocekivao da i ovde dobijem adresu od (a).(?)

2)
Prethodno pitanje je postavljeno, u stvari, zbog ove definicije konstruktora:
Code:

52:    // Converts a character array to a String
53:   String::String(const char * const cString)
54:    {
55:       itsLen = strlen(cString);
56:       itsString = new char[itsLen+1];
57:       for (unsigned short i = 0; i<itsLen; i++)
58:          itsString[i] = cString[i];
59:       itsString[itsLen]='\0';
60:    }


i ovog poziva (koji ga koristi):

145: String s1("initial test");


Pokazivac bi trebalo da se inicijalizuje adresom pokazivanog objekta, u ovom slucaju, stringa "initial test", tj. karaktera(i).
Izgleda (nije objasnjeno, do sada), da navodnici oko stringa vracaju njegovu adresu (jer imamo npr. char *temp = "Hello World";), i tako se postavlja pointer u gornjem konstruktoru, ali ostaje nejasno kako cString predstavlja "initial test".
Hocu da kazem, ocekivao sam u gornjoj definiciji, svuda gde se pojavljuje cString, (*) ispred njega, jer, po meni, cString je samo adresa a ne string.


Hvala

[Ovu poruku je menjao Pretender dana 02.10.2003. u 22:29 GMT]
 
Odgovor na temu

[es] :: C/C++ programiranje :: copy konstruktor

Strane: 1 2

[ Pregleda: 7738 | Odgovora: 22 ] > FB > Twit

Postavi temu Odgovori

Navigacija
Lista poslednjih: 16, 32, 64, 128 poruka.