In che modo la durata di un valore di ritorno è estesa all’ambito della funzione chiamante quando è associata a un riferimento const nella funzione chiamante?

“Se restituisci un valore (non un riferimento) dalla funzione, quindi associalo a un riferimento const nella funzione chiamante, la sua durata verrà estesa all’ambito della funzione chiamante.”

Quindi: CASO A

const BoundingBox Player::GetBoundingBox(void) { return BoundingBox( &GetBoundingSphere() ); } 

Restituisce un valore di tipo const BoundingBox dalla funzione GetBoundingBox()

variante I: (associamola a un riferimento const)

 const BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox(); 

variante II: (associare a una copia const)

     const BoundingBox l_Bbox = l_pPlayer->GetBoundingBox(); 

    Entrambi funzionano bene e non vedo l’object l_Bbox uscire dall’ambito. (Però, capisco nella variante uno, il costruttore di copie non viene chiamato e quindi è leggermente migliore della variante II).

    Inoltre, per confronto, ho apportato le seguenti modifiche.

    CASO B

     BoundingBox Player::GetBoundingBox(void) { return BoundingBox( &GetBoundingSphere() ); } 

    con Varianti: I

     BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox(); 

    e II:

     BoundingBox l_Bbox = l_pPlayer->GetBoundingBox(); 

    L’object l_Bbox continua a non uscire dall’ambito. In che modo “collegarlo a un riferimento const nella funzione chiamante, la sua durata verrebbe estesa all’ambito della funzione chiamante”, si estende davvero la durata dell’object all’ambito della funzione chiamante?

    Mi sto perdendo qualcosa di banale qui?

    Normalmente un object temporaneo (come quello restituito da una chiamata di funzione) ha una durata che si estende fino alla fine dell ‘”espressione di chiusura”. Tuttavia, un vincolo temporaneo a un riferimento generalmente ha la durata “promossa” per tutta la vita del riferimento (che può o non può essere la durata della funzione di chiamata), ma ci sono un paio di eccezioni. Questo è coperto dallo standard in 12.2 / 5 “Oggetti temporanei”:

    Il temporaneo al quale il riferimento è vincolato o il temporaneo che è l’object completo di un suboggetti di cui il temporaneo è vincolato persiste per la durata del riferimento eccetto come specificato di seguito. Un vincolo temporaneo a un membro di riferimento nel ctor-initializer di un costruttore (12.6.2) persiste finché il costruttore non si chiude. Un vincolo temporaneo a un parametro di riferimento in una chiamata di funzione (5.2.2) persiste fino al completamento dell’espressione completa che contiene la chiamata.

    Vedere quanto segue per ulteriori informazioni:

    • Durata di riferimento costante C ++ (adattatore contenitore)
    • GotW # 88: un candidato per il “più importante const”

    Un esempio che potrebbe aiutare a visualizzare cosa sta succedendo:

     #include  #include  class foo { public: foo( std::string const& n) : name(n) { std::cout << "foo ctor - " << name + " created\n"; }; foo( foo const& other) : name( other.name + " copy") { std::cout << "foo copy ctor - " << name + " created\n"; }; ~foo() { std::cout << name + " destroyed\n"; }; std::string getname() const { return name; }; foo getcopy() const { return foo( *this); }; private: std::string name; }; std::ostream& operator<<( std::ostream& strm, foo const& f) { strm << f.getname(); return strm; } int main() { foo x( "x"); std::cout << x.getcopy() << std::endl; std::cout << "note that the temp has already been destroyed\n\n\n"; foo const& ref( x.getcopy()); std::cout << ref << std::endl; std::cout << "the temp won't be deleted until after this...\n\n"; std::cout << "note that the temp has *not* been destroyed yet...\n\n"; } 

    Che visualizza:

     foo ctor - x created foo copy ctor - x copy created x copy x copy destroyed note that the temp has already been destroyed foo copy ctor - x copy created x copy the temp won't be deleted until after this... note that the temp has *not* been destroyed yet... x copy destroyed x destroyed 

    In primo luogo, la durata dell’object temporaneo viene estesa alla durata del riferimento const che è associato ad esso, non “all’ambito della funzione chiamante” (sebbene forse ciò che intendevi per quella strana espressione “l’ambito della funzione chiamante”) . Questo è ciò che illustra la tua CASE A , dove si collega un riferimento const a un temporaneo. Il temporaneo continua a vivere finché il riferimento vive. Quando il riferimento termina la sua vita, anche l’object temporaneo viene distrutto.

    In secondo luogo, il tuo CASE B è semplicemente mal formato, non compilabile. Vale a dire, il

     BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox(); 

    è illegale. In C ++ è illegale colbind un riferimento non const a un temporaneo. Se il tuo compilatore lo consente, deve essere una stranezza / estensione del tuo compilatore, che ha poco a che fare con il linguaggio C ++.

    Il punto è che quando si restituisce un valore, il valore viene copiato nella variabile a cui si assegna il risultato della funzione. (come hai detto tu – viene chiamato il costruttore di copie ). Nessuna estensione a vita, basta creare un object nuovo di zecca.

    Quando si torna per riferimento, sotto il cofano si passa semplicemente il puntatore alla variabile definita nella funzione. Quindi, non viene creato un nuovo object, basta fare riferimento ad esso al di fuori della funzione. Con questo caso la durata di una variabile funzione-interna viene estesa.

    Di solito, se si restituisce un object in base al valore di una funzione, l’object suddetto verrà distrutto quando l’espressione dell’assegnazione è terminata:

     myclass X = getX(); // after copy constructor, the returned value is destroyed // (but you still hold a copy in X) 

    Nel caso che descrivi, il valore restituito verrà distrutto in seguito, permettendoti di usarlo:

     const myclass& X = getX(); cout << Xa << endl; // still can access the returned value, it's not destroyed