Assegnazione Rvalore restituito dalla funzione a un altro valore Rvalue

class Test { public: int n1; }; Test func() { return Test(); } int main() { func() = Test(); } 

Questo non ha senso per me. Come e perché è permesso? È un comportamento indefinito? Se una funzione restituisce un valore, allora come è ansible impostare un rvalue su un altro valore? Se ho provato questo con qualsiasi tipo primitivo, mi darebbe un errore come mi aspetto.

So che i lvalues ​​sono un posto in memoria, quindi la funzione crea un lvalue temporaneo (rvalue?) E lo assegna ad un altro lvalue? Qualcuno può spiegare come funziona questa syntax?

La categoria di valore dell’espressione di chiamata di funzione è in effetti un valore.

In effetti, non è ansible chiamare l’operatore di assegnazione delle copie su primitive di valore. La definizione storica di rvalues ​​in C era in realtà la distinzione che essi non possono essere sul lato sinistro di un asserzione.

Gli operatori di assegnazione delle classi sono un po ‘diversi, però. Sono funzioni membro regolari. E nessuna regola impedisce di chiamare funzioni membro di rvalue. In effetti, è spesso abbastanza utile quando le funzioni hanno effetti collaterali.

Come funziona, beh, l’operatore di assegnazione delle copie è chiamato sul temporaneo, l’operatore copia l’argomento della mano destra, cambiando lo stato del temporaneo. Dopo l’istruzione, l’object temporaneo viene scartato. Non c’è UB, solo una copia inutile.

È ansible impedire l’assegnazione della copia chiamante su un valore di rvalue, dichiarando all’operatore un qualificatore di riferimento come questo: Test& operator=(Test) & = default; . I qualificatori di riferimento sono stati aggiunti solo più tardi in c ++ 11, quindi non è stato ansible specificare (implicito) l’assegnazione della copia per essere qualificata per il ref-in prima. Presumibilmente, C ++ 11 non ha modificato il qualificatore del costruttore di copie implicite per evitare di rompere il vecchio codice che assegna a un valore rvalore, anche se tale assegnazione sembra abbastanza inutile. Lo standard di codifica C ++ ad alta integrità consiglia di utilizzare il qualificatore di riferimento con operatori di assegnazione copia definiti dall’utente.

C’è una curva di apprendimento piuttosto ripida per quanto riguarda le categorie di valore (almeno per me), ma credo che tu abbia la terminologia giusta sul tuo esempio. Così

 func() 

restituisce infatti un valore e dal Par standard C ++. 3.10.5 (Ho solo la bozza attuale, il tuo numero di paragrafo può variare) leggiamo:

Un lvalue per un object è necessario per modificare l’object, tranne per il fatto che un rvalue di tipo di class può essere utilizzato anche per modificare il suo referente in determinate circostanze . [Esempio: una funzione membro chiamata per un object (9.3) può modificare l’object. – esempio finale]

Quindi l’operatore di assegnazione, che è una funzione membro, come nell’esempio menzionato nello standard è un’eccezione alla regola, consentendo la modifica dei valori.

Questo ha generato molte critiche nel mondo della programmazione, con il suo esempio più estremo questo estratto FQA del C ++ :

(Sì, trappole mortali ricoperte di zucchero, tu cheerleader senza tracce X& obj=ab().c() – oops, b() è un object temporaneo e c () restituisce un riferimento in esso! Non dovrebbe averlo assegnato a un riferimento. Non ci sono molte possibilità per un avvertimento del compilatore.)

Ma nella programmazione C ++ reale ha applicazioni industriali come l’idioma dei parametri chiamato :

 std::cout << X::create().setA(10).setB('Z') << std::endl;