2013-02-06 10 views
18

mi è stato mostrato il seguente esempio in videochat:Quale standard standard ci dice che l'estensione di durata temporanea ref-to-const solo "funziona una volta"?

#include <iostream> 
struct foo { ~foo() { std::cout << "destroying!\n"; } }; 
const foo& func(const foo& a, const foo&) { return a; } 

int main() 
{ 
    foo x; 
    const foo& y = func(foo(), x); 
    std::cout << "main\n"; 
} 

Output:

destroying! 
main 
destroying! 

Sembra dimostrare che la durata del foo temporanea non è esteso a totalità del main, anche se si arriva associato a un ref-to-const in tale ambito.

Presumibilmente, quindi, l'estensione di durata solo "funziona una volta"; vale a dire, viene applicato quando gli argomenti di func vengono inizializzati, ma non vengono trasmessi tramite binding consecutivi.

La mia interpretazione è corretta? Se è così (e se ogni singolo paragrafo è direttamente applicabile) qual è la dicitura standard che definisce questo comportamento?

+0

Qual è il secondo argomento per 'func'? Cosa succede se si lascia (e 'x') spento? –

+0

@KonradRudolph: È per dimostrare l'ordine di distruzione relativo all'output del testo '" main "', immagino. –

risposta

7

Questo è soggetto a due rapporti di emissione, http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1299 e http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1568.

Il precedente rapporto di emissione, di cui sono il giornalista, era destinato a coprire tutti questi casi in cui un riferimento è legato a un oggetto temporaneo, ma non è destinato ad essere esteso per tutta la vita. La descrizione nel corpo del problema menziona solo i valori prenati confusi con espressioni temporanee (che in realtà decidono se la durata di ciò che valutano è allungata o meno). Ma lvalue e xvalues ​​sono ugualmente confusi con questi nello Standard. Un esempio in cui ciò accade nel contesto di static_cast è il numero di rilascio # 1568 (in cui l'uso della "variabile temporanea" confonde ulteriormente la questione).

realtà, questo:

Un temporaneo legato a un parametro di riferimento in una chiamata di funzione (5.2.2) persiste fino al completamento dell'espressione completa contenente la chiamata.

Contraddisting le altre regole nello stesso paragrafo. Poiché il temporaneo è associato a sia un parametro di riferimento in una chiamata di funzione e a una variabile di riferimento automatica locale.

+0

Sì, ok, tu e James mi avete convinto che la parola "tranne" non disambigura le regole del paragrafo, perché "eccetto" viene ancora applicato solo a un singolo scenario alla volta, e come tale non può disambiguare due o scenari più conflittuali. –

8

Hai quasi ragione. Questo comportamento deriva in realtà dalla chiamata della funzione in particolare, non a causa di una sorta di regola "funziona solo una volta".

Ecco il testo della vita intera estensione "caratteristica", con la regola pertinente sottolineato in grassetto:

[C++11: 12.2/5]:[..] La temporanea a cui è legato il riferimento o la temporanea che è l'oggetto completo di un oggetto secondario a cui è legato il riferimento persiste per tutta la durata del rinvio tranne:

  • [..]
  • Un collegamento 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.
  • [..]
+0

Ma in questo caso, il temporaneo è anche associato al riferimento const 'y'. Quindi, quale riferimento controlla la sua vita? –

+1

@JamesKanze: Vedo che la lista "tranne" ha la precedenza. –

+0

Capisco cosa intendi, ma continuo a pensare che sia ambiguo, e se questo è l'intento, un modo tortuoso di specificarlo. In primo luogo, garantisci una durata estesa basata unicamente sul fatto che il riferimento sia legato o meno a un temporaneo, quindi elimini tutti i casi che potrebbero portare a un riferimento indiretto, sperando che tu li abbia ottenuti tutti (cosa che probabilmente non hanno) . –

3

La regola che si applica qui è il senso comune. Lo standard è mal scritto, e di fatto lo garantisce. Ma non c'è un modo pratico per implementarlo con lo .

+0

Cosa intendi? Nessun modo pratico per implementare la restrizione o per implementare l'estensione della durata che attualmente non si verifica? –

+0

@LightnessRacesinOrbit Non esiste un modo pratico per forzare la durata di un temporaneo ad estendersi all'ultimo riferimento a cui è associato. –

+0

Penso che @James stia parlando di ciò che riassumo nella mia risposta. –

1

Probabilmente sono un po 'lento ma per me non è diventato chiaro quale sia la risoluzione di questa domanda dalla lettura delle altre risposte. Così ho modificato il codice mostrato e volevo riassumerlo per gli altri: la risposta è, si ottiene comportamento indefinito se si accede a !

eseguire questo codice:

struct foo { 
    int id; 
    foo(int id) : id(id) { std::cout << "ctor " << id << std::endl; }; 
    ~foo() { std::cout << "dtor " << id << std::endl; } 
}; 
const foo& func(const foo& a, const foo&) { return a; } 

int main(int argc, char** argv) { 
    foo x(1); 
    const foo& y = func(foo(2), x); 
    std::cout << "main " << y.id << std::endl; 
    return 0; 
} 

L'uscita per me è:

ctor 1 
ctor 2 
dtor 2 
main 2 
dtor 1 

Ma la linea è main 2comportamento indefinito.

Problemi correlati