Ci sono alcuni problemi con il codice che ha iscritto, per esempio.
Student::Student (const Student&& stud):
matricola{stud.matricola},
name{stud.name},
surname{stud.name},
materie{stud.materie}
{
stud.materie.~vector(); //necessario?
stud.~Student();
}
Il costruttore di spostamento deve prendere il suo parametro come r-value reference cioè Student&&, perché questo ? Perché quando usi il costruttore di movimento dovresti spostare tutte le informazioni dalla variabile di input nella variable in cui stai spostando (puntatore this), però se dichiari la r-value reference const non sarà possibile modificare il contenuto di essa.
Seconda cosa, non dovresti mai chiamare il destructor per i membri della variabile stud o per stud, perché alla fine del costruttore di movimento verrà chiamato il destructor per la variabile stud,se lo chiami anche tu saranno due chiami al destructor e due chiamate al destructor sono undefined behaviour.
Student& Student::operator=(const Student& stud){
name.~string(); //necessari?
surname.~string();
materie.~vector();
matricola={stud.matricola}; //non hai bisogna delle parentesi per chiamare l'operatore di copia !
name={stud.name};
surname={stud.surname};
vector<Corso*> newmatr(stud.materie);// questa variabile non ti serve, poi assegnare direttamente a "materie", sempre se ogni
//studente non deve avere una sua copia del corso
materie=newmatr;
return *this;
}
Le chiamate esplicite ai destructor non sono necessari, perché 100% quando chiami l'operatore= per string e vector essi si occupano a liberare le informazioni per i vecchi elementi. Le chiamate esplicite combinate con la mancanza di self-assignment possono solo portare ad un disastro, per esempio se faccio una cosa come questa
Studente a{/*variabili*/};
a=a;
Cancellerai le informazioni dell'oggetto senza accorgertene ! Per evitare problemi l'operatore di copia deve essere scritto tipo cosi
T& operator=(const T& rhs)
{
if(this!=&rhs)
{
//Codice di assignment qui
}
return *this;
}
Per quanto riguarda la tua ultima domanda, è semplice distinguere tra un T& e T&&. Il primo è una variabile che alla fine della expression esisterà ancora, invece la seconda è una variabile che alla fine della expression non esisterà più quindi è possibile spostare le informazioni da essa.
Per esempio
Student getStudent()
{
return Student{};
}
Student a=getStudente();
In questo caso alla fine della chiamata alla funzione lo Student creato dalla funzione è temporaneo quindi verrà chiamato il costruttore di movimento visto alla fine della expression lo Student ritornato sarà scartato.Ricorda sempre che se la variabile a cui stai assegnando è già inizializzata verrà chiamato l'operatore di spostamento !
Comunque non è detto che l'oggetto che ritorna getStudent() verrà creato, vedi Copy elission e RVO !
Invece per minimizzare la duplicazione di codice tra gli operatori di spostamento/movimento vedi il Copy Swap Idiom