[C++] dubbio su assegnazione profonda

bandido
Buongiorno
non capisco una cosa riguardante l'assegnazione "profonda".
Nel seguente codice:
class C {
public:
    C(): size(1), a(new int[1]) {a[0]=0;}
    C& operator=(const C& x) { //overloading operatore = , la fonte dei miei dubbi...
           if(this!=&x){
            size=x.size;
            a=new int[size];
            for(int i=0;i<size;i++) a[i]=x.a[i];
          }
          return *this;
    }
    void add(int k) { 
      int *b=a;
          a=new int[size+1];
          ++size;
          a[0]=k;
          for(int i=1;i<size;i++) a[i]=b[i-1];
          delete[] b;
    }
    int& operator[](int i) const {return a[i];}
    void stampa() const {
          for(int i=0;i<size;i++) cout<<a[i]<< ’ ’;
    }
      ~C() {stampa(); cout<<" ~C"; delete[] a;}
private:
    int size;
    int* a;
};
main(){
    C v; v.add(1);
    C w=v; w[1]=2;
    v.stampa(); cout<<"UNO\n";
    w.stampa(); cout<<"DUE\n";
//il codice continua, ma quel che mi interessa è qua
}


Cioè creo un oggetto v, con un solo elemento [0], quindi invoco add su di esso e quindi diventa v[0,1].
poi creo w=v, cioè w[0,1]. Poi assegno w[1]=2, quindi w[2,1], e fin qui tutto bene.

ma perchè adesso anche v è diventato [1,2]??? secondo me dovrebbe essere ancora [0,1].... dove sbaglio?

un grazie a tutti coloro che mi vorranno rispondere

[mod="Raptorista"]Sistemo i tag per visualizzare il codice. Attenzione la prossima volta, non sei più un novellino del forum! :evil: [/mod]

Risposte
ema901
w=v non è una copia come pensi
se tu hai x e y interi e fai x=y funziona , cioè assegna il valore di y a x ma con gli oggetti non funziona così , x e y diventano puntatori e se fai x=y , poi modifichi x , automaticamente viene modificato anche y poichè puntano alla stessa cosa , in poche parole non hai fatto una copia profonda.

Per fare una copia profonda devi implementare un metodo clone() che crea una nuova istanza dell'oggetto e fa la copia dei valori uno ad uno.

apatriarca
@ema90: credo che tu sia abituato con linguaggi come Java, in C++ non funziona per niente in quel modo. Puntatori e reference vanno dichiarati in modo esplicito utilizzando * o &.

@bandido: dichiarando una variabile in quel modo, si ha una nuova istanza della classe che viene allocata nello stack. Questa variabile sarà inizializzata attraverso il costruttore di copia, quello presente nella classe se presente o quello di default in caso contrario. Il costruttore di copia di default copia ogni variabile membro da una classe all'altra. L'operatore di assegnamento viene richiamato invece tra due oggetti già costruiti. Se avessi quindi scritto
C w;
w = v;

avresti fatto uso dell'operatore di assegnamento che hai scritto. Non è certamente una delle cose più intuitive e ben riuscite del C++ secondo me, ma si deve convivere con questa cosa. Per far funzionare il tuo codice devi quindi implementare un nuovo costruttore di copia e aggiustare il tuo operatore di assegnamento che non tiene conto del fatto che la classe esiste già (devi quindi deallocare la memoria una volta puntata da a). Devi quindi avere entrambe queste funzioni nella classe:
C(const C& x) {
    size = x.size;
    a = new int[size];
    for (int i = 0; i < size; ++i) a[i] = x.a[i];
}

C& operator=(const C& x) {
    if (this != &x) {
        delete[] a; // a punta a qualcosa..
            
        size = x.size;
        a = new int[size];
        for (int i = 0; i < size; ++i) a[i] = x.a[i];
    }
    return *this;
}


Ci sono però anche altri errori nel tuo ragionamento.

Cioè creo un oggetto v, con un solo elemento [0], quindi invoco add su di esso e quindi diventa v[0,1].


Non è quello che fa la funzione add. Se studi meglio il codice, vedrai infatti che aggiunge all'inizio dell'array e non alla fine! In v avrai quindi [1, 0] e non [0, 1]. A questo punto viene creato w e avrà quindi anche lui [1, 0] come contenuto. Assegni allora a w[1] il valore 2 ottenendo quindi [1, 2]

Non hai poi incluso la libreria come dovrebbe essere necessario e main deve restituire int e non può essere lasciata senza valore di ritorno (anche se alcuni compilatori lo permettono è contro lo standard).

bandido
grazie mille apatriarca... adesso mi è molto più chiaro!
stupido errore da parte mia ;-)

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.