Che cosa sta succedendo ?
Quando si crea un Taxi, si crea anche un Caroggetto secondario. E quando il taxi viene distrutto, entrambi gli oggetti vengono distrutti. Quando chiami test(), passi il Carvalore. Quindi un secondo Carviene copiato e verrà distrutto quandotest() viene lasciato. Quindi abbiamo una spiegazione per 3 distruttori: il primo e i due ultimi della sequenza.
Il quarto distruttore (che è il secondo nella sequenza) è inaspettato e non ho potuto riprodurlo con altri compilatori.
Può essere solo un temporaneo Carcreato come fonte per l' Carargomento. Dal momento che non accade quando si fornisce direttamente un Carvalore come argomento, ho il sospetto che sia per trasformarlo Taxiin Car. Ciò è inaspettato, poiché esiste già un Caroggetto secondario in ogni Taxi. Pertanto, penso che il compilatore non effettui una conversione non necessaria in una temp e non esegua la copia elisione che avrebbe potuto evitare questa temp.
Chiarimento fornito nei commenti:
Qui il chiarimento con riferimento alla norma per l'avvocato linguista per verificare le mie affermazioni:
- La conversione a cui mi riferisco qui è una conversione per costruttore
[class.conv.ctor], ovvero la costruzione di un oggetto di una classe (qui Car) basato su un argomento di altro tipo (qui Taxi).
- Questa conversione utilizza quindi un oggetto temporaneo per restituire il suo
Carvalore. Al compilatore sarebbe consentito effettuare una copia elisione secondo [class.copy.elision]/1.1, poiché invece di costruire un temporaneo, potrebbe costruire il valore da restituire direttamente nel parametro.
- Quindi, se questa temperatura produce effetti collaterali, è perché il compilatore apparentemente non utilizza questa possibile copia-elisione. Non è sbagliato, dal momento che l'elezione della copia non è obbligatoria.
Conferma sperimentale dell'analisi
Ora potrei riprodurre il tuo caso usando lo stesso compilatore e disegnare un esperimento per confermare cosa sta succedendo.
La mia ipotesi di cui sopra era che il compilatore ha selezionato un parametro non ottimale passando il processo, usando la conversione del costruttore Car(const &Taxi)invece della copia della costruzione direttamente dal Caroggetto secondario di Taxi.
Quindi ho provato a chiamare test()ma esplicitamente lanciando il file Taxia Car.
Il mio primo tentativo non è riuscito a migliorare la situazione. Il compilatore utilizzava ancora la conversione del costruttore non ottimale:
test(static_cast<Car>(taxi)); // produces the same result with 4 destructor messages
Il mio secondo tentativo è riuscito. Fa anche il casting, ma usa il pointer pointer per suggerire fortemente al compilatore di usare l' Caroggetto secondario Taxidell'oggetto e senza creare questo stupido oggetto temporaneo:
test(*static_cast<Car*>(&taxi)); // :-)
E sorpresa: funziona come previsto, producendo solo 3 messaggi di distruzione :-)
Esperimento conclusivo:
In un esperimento finale, ho fornito un costruttore personalizzato per conversione:
class Car {
...
Car(const Taxi& t); // not necessary but for experimental purpose
};
e implementarlo con *this = *static_cast<Car*>(&taxi);. Sembra sciocco, ma questo genera anche codice che visualizzerà solo 3 messaggi di distruttore, evitando così l'oggetto temporaneo non necessario.
Questo porta a pensare che potrebbe esserci un bug nel compilatore che causa questo comportamento. È una possibilità che in alcune circostanze manchi la possibilità di costruire copie dirette dalla classe base.
Taxioggetto a una funzione che prende unCaroggetto in base al valore?