Differenza copia e spostamento

di il
5 risposte

Differenza copia e spostamento

Ciao a tutti, mi servirebbe una delucidazione su copia e spostamento, il codice fa solo lo scambio di due valori
Per lo spostamento (volendo trasferire un valore da A a B) sul mio libro sta scritto "lo spostamento lascia A con il precedente valore di B e B con uno stato di origine di spostamento" oppure viene descritta come una "lettura distruttiva" ma quindi al livello di macchina che succede? Con A=B ho una copia bit a bit e invece con lo spostamento che fa il pc?
In piu' se è una lettura distruttiva com'è possibile che riesco a stampare ancora "a" dopo averne estratto rvalue?(nel codice stampo "a" prima e dopo la creazione di "tmp")

E infine cosa si intende con "stato di origine di spostamento"?

#include <iostream>
using namespace std;

template<typename T>
void scambio(T& a,T& b){
    cout<<a<<" ";
    T tmp=static_cast<T&&>(a);
    cout<<a;
    a=static_cast<T&&>(b);
    b=static_cast<T&&>(tmp);
}

int main(){
    int a=10;
    int b=2;
    scambio(a,b);

    return 0;
}

5 Risposte

  • Re: Differenza copia e spostamento

    Mettila in questo modo:

    supponi di avere una funzione che RITORNA un ""std::vector"" contenente 1.000.000 di elementi, ed uno statement del tipo:
    
    extern std::vector<Debiti> debitiDi(const std::string& who)
    
    std::vector<Debiti> debiti = debitiDi("Paperino");
    
    il comportamento standard dovrebbe essere:

    1) viene popolato il vettore usato dalla funzione come valore di ritorno
    2) viene vuotato "debiti"
    3) viene COLONATO il contenuto del risultato della funzione e messo in "debiti"
    4) viene BUTTATO VIA il vettore ritornato dalla funzione.

    in 1) hai allocato un vettore per UN MILIONE di elementi
    in 3) ti serve spazio per allocare un'ALTRO MILIONE di elementi e anche il TEMPO necessario per fare la copia
    in 4) BUTTI VIA il primo vettore, rilasciando la memoria allocata allo heap (operazione che richiede tempo)

    con lo ""spostamento""

    1) rimane lo stesso
    2) anche
    3) SPOSTI il contenuto del vettore ritornato dalla funzione DIRETTAMENTE in "debiti". QUINDI non ti serve allocare altra memoria e, di conseguenza, non perdi tempo
    4) rimane lo stesso MA in questo caso butti via un vettore VUOTO.


    Ovviamente, nell'operazione di SPOSTAMENTO devi mantenere la coerenza su DUE oggetto: l'oggetto sorgente E l'oggetto destinazione.
  • Re: Differenza copia e spostamento

    Certo che è un modo orribile, da parte del libro, per introdurre l'argomento.

    Prendi ad esempio una classe Lista, che ha al suo interno il puntatore al primo elemento della lista. Il costruttore di copia-spostamento, invece di copiare tutta la lista, copia solo il puntatore da b in a e azzera il puntatore in b, quindi ha trasferito il controllo della lista ad a.
    Ovviamente un costruttore che fa questo va implementato a mano e se non lo fai, si attiva in automatico la copia normale. I contenitori della libreria standard, ad esempio std::vector, std::string, ecc... ne hanno implementato uno per poter fare lo spostamento.

    L'espressione:
    a = static_cast<T&&>(b)
    riallacciandomi a quanto detto da @migliorabile, dice al compilatore "vedi b come se fosse un oggetto temporaneo di tipo T, ad esempio un valore restituito da una funzione", in questo modo il compilatore è legittimato ad effettuare lo spostamento, resettando b.

    La stessa espressione si ottiene più agevolmente in questo modo:
    
    #include <utility>
    using namespace std;
    //...
    a = move(b);
    
  • Re: Differenza copia e spostamento

    Grazie mille così è già molto piu' chiaro mi rimane solo un ultimo dubbio
    "a" e "b" sono due vettori allocati dinamicamente dopo aver fatto "a=move(b)" ho che posso stampare ancora il vettore b, ma come è possibile se il puntatore di b è stato azzerato che questo si riferisca ancora a tale locazione di memoria? In piu' se modifico "a" viene modificato anche "b", quindi ne deduco che il puntatore di b non è posto a "nullptr" ma sia "a" che "b" puntano alla stessa locazione di memoria
    #include <iostream>
    #include <utility>
    using namespace std;
    
    template<typename T>
    void scambio(T& a,T& b){
        
        T tmp=move(a);
        for(int i=0;i<3;i++)cout<<b[i];
        cout<<'\n';
        
        a=move(b);
        a[0]=0;
        
        for(int i=0;i<3;i++)cout<<b[i];
        b=move(tmp);
    }
    
    int main(){
        
        int *a=new int[3];
        for(int i=0;i<3;i++)a[i]=i;
        
        int *b=new int[3];
        for(int i=0;i<3;i++)b[i]=i+3;
        
        scambio(a,b);
    
        return 0;
    }
  • Re: Differenza copia e spostamento

    Lo spostamento è pensato per le classi (o struct) di oggetti che posseggono puntatori al loro interno, sulle quali va definito l'apposito costruttore di copia-spostamento, il quale si occupa del trasferimento della proprietà e l'azzeramento dell'oggetto in ingresso.
    Il linguaggio evidentemente non ne ha definito uno implicito sul puntatore nudo, quindi si limita ad attivare la copia bit a bit.
    La funzione move, a dispetto del nome, non fa niente di particolare, è soltanto un surrogato dello static_cast<T&&> di cui sopra.
  • Re: Differenza copia e spostamento

    Grazie mille, infatti se uso vector al posto del vettore allocato dinamicamente durante l'esecuzione mi da errore
Devi accedere o registrarti per scrivere nel forum
5 risposte