2014-04-14 22 views
26

In http://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/ si menziona "most important const" dove C++ specifica deliberatamente che legare un oggetto temporaneo a un riferimento a const sullo stack allunga la durata del temporaneo alla durata del riferimento stesso. Mi chiedevo perché il C++ consente di allungare la vita dell'oggetto solo quando il riferimento è const e non quando non lo è? Qual è il razionale dietro la funzione e perché deve essere const?Perché la "più importante const" deve essere const?

+1

Sto sperando in una citazione da The Standard qui, dal momento che non sono mai riuscito a convincermi che * * richiede il 'const'. (Osservando 12.2 p4 e 5 in N3936). – BoBTFish

+0

In modo che il compilatore non debba verificare che nessun percorso modifichi il temporaneo prima che l'oggetto esca dall'ambito. –

+4

@BoBTFish: stai osservando la durata dei temporaries legati ai riferimenti. Per le regole su come vincolarli, vedere [dcl.init.ref] (8.5.3 in C++ 11). In particolare, il punto finale di p5: "il riferimento deve essere un riferimento di lvalue a un tipo non volatile ** const ** [o] un riferimento di valore." –

risposta

14

Si consideri il seguente:

int& x = 5; 
x = 6; 

quello che dovrebbe accadere se questo è stato permesso? Al contrario, se l'avete fatto

const int& x = 5; 

non ci sarebbe alcun modo legale per modificare x.

+0

Dovrebbe essere creata una variabile locale nascosta con valore 5. Non c'è motivo tecnico per non permetterlo. –

+1

@NeilKirk Tuttavia, non è qualcosa che ci si aspetta da 'int &', sarebbe solo un peso per i progettisti del compilatore e non sarebbe diverso da 'int x = 5'. –

+2

@tohecz ma questo è il modo in cui il binding con const è implementato con i valori restituiti dalle normali funzioni. Tutte le funzionalità sono "fardelli" per i progettisti del compilatore, non è un motivo per non essere una caratteristica! – dan

24

Ecco un esempio:

void square(int &x) 
{ 
    x = x * x; 
} 

int main() 
{ 
    float f = 3.0f; 

    square(f); 

    std::cout << f << '\n'; 
} 

Se provvisori potrebbero legarsi a riferimenti lvalue non const, quanto sopra sarebbe felicemente compilare, ma produrre risultati piuttosto sorprendenti (una potenza di 3 invece di 9).

+0

Interessante, non ci avevo pensato. –

+2

Perché dovrebbe emettere 3? – 0x499602D2

+0

Questa è la solita spiegazione, penso. Cosa accadrebbe se fosse consentito nell'inizializzazione in stile copia, ma non nell'inizializzazione dei parametri? Esistono già conversioni esplicite o implicite. –

1

Si noti che i riferimenti const possono essere associati a oggetti che non hanno nemmeno un indirizzo normalmente. Un parametro di funzione const int & può accettare un argomento formato dall'espressione costante letterale 42. Non possiamo prendere l'indirizzo di 42, quindi non possiamo passarlo a una funzione che prende uno const int *.

I riferimenti const sono appositamente "benedetti" per poter essere associati a valori come questo.

Ovviamente, per i rvalori tradizionali come 2 + 2, la durata non è un problema. È un problema per i rvalues ​​del tipo di classe.

Se il legame di un riferimento è consentito a qualche oggetto che, a differenza 42, non hanno una vita diffusa, quella vita ha da estendere, in modo che il riferimento rimane sano per tutta la sua portata.

Non è che il const causi un'estensione di durata, è che un riferimento non const non è consentito. Se fosse permesso, richiederebbe anche un'estensione a vita; non ha senso permettere qualche riferimento che poi va male in alcune parti del suo campo di applicazione. Questo comportamento mina il concetto che un riferimento sia più sicuro di un puntatore.

Problemi correlati