2012-12-11 15 views
35

C++ consente l'assegnazione di oggetti temporanei solo al riferimento const. Non consentirà l'assegnazione di oggetti temporanei a riferimento.Perché non riferimento non const a oggetti temporanei?

Ad esempio:

String& a = String("test");   // Error 
const String& a = String("test"); // Ok 

Ovunque Google per questo risultato, vedo solo le seguenti risposte

  1. Modifica oggetti temporanei causerebbe problemi non identificabili
  2. Modifica oggetti temporanei è pericoloso
  3. Ad un certo punto del tempo, ti dimenticherai che è una variabile temporanea

Si è detto, gli oggetti temporanei svaniscono dopo la dichiarazione. Quindi non dovresti modificarlo.

Se C++ è così appassionato nel bloccare la modifica degli oggetti temporanei, dovrebbe aver bloccato la lettura degli oggetti temporanei giusto? Se l'oggetto temporaneo è sparito, non ha senso leggere i contenuti da lì giusto? I casi possibili, in cui può verificarsi un diritto, potrebbero anche comportare la lettura.

Quindi perché ha bloccato la scrittura da sola e consentendo la lettura?

Per favore dammi una spiegazione del codice C++ solido.

Si prega di non deviare la domanda indicando alcune alternative. Per favore, dammi una risposta valida con il codice perché const int & è consentito e int & non è consentito per oggetti temporanei.

Uno dice & & è lì .. La mia domanda diversa .. altro dire, cambiando non rifletterà .. La modifica non rifletterà anche quando è const int & troppo. Ad esempio: doppio a; Const int & i = a; a ++; non influenza i ..

+0

Non sono sicuro di aver capito la domanda. [Questo] (http://stacked-crooked.com/view?id=49e766dcb26e7f773e3b497c2ff41a52) conta come una lettura temporanea? Se stai parlando di uno che è passato a una funzione, devi copiarlo, spostarlo o usare un riferimento const, che estende la sua durata. – chris

+0

+1 Mi sono chiesto anche questo. – Mehrdad

+0

Penso che sia molto difficile analizzare tutti i riferimenti a un oggetto per gli autori di compilatori per fornire garanzie. –

risposta

3

Se si dispone di un oggetto temporaneo molto costoso da copiare, è preferibile prendere un const& per quell'oggetto (ad esempio una funzione di ritorno) anziché copiarlo in un'altra variabile da utilizzare in un secondo momento. Prendendo un riferimento costante a un temporaneo estende la vita di quel temporaneo fino a quando il riferimento vive, permettendoti di accedere a qualsiasi stato leggibile.

La scrittura non è consentita perché non appena si desidera modificare una variabile si può anche avere un'istanza reale piuttosto che una temporanea che è alias solo come riferimento non const.

+1

"Prendendo un riferimento costante a un temporaneo estende la vita di quel temporaneo fino a quando il riferimento vive" ... cosa? Questo è vero solo se stanno passando un oggetto reale, non ad es. un altro riferimento const ad esso. E non spiega perché i riferimenti non const non potrebbero fare lo stesso. – Mehrdad

+0

@ Mehrdad la domanda sembra indicare chiaramente l'assunzione di un riferimento const a un oggetto temporaneo di valore effettivo. Forse ho mal interpretato l'intenzione dell'OP. –

+0

"non appena si desidera modificare una variabile, si può anche avere un'istanza reale", precisamente, +1 –

22

Il caso originale per non consentire riferimenti a provvisori era per i parametri di funzione. Supponiamo che questo fosse permesso:

void inc(double& x) 
{ x += 0.1; } 

int i = 0; 
inc(i); 

Perché non è stato modificato i?

+0

Non si può fare solo un errore in fase di compilazione? (Non è vero?) Non sono sicuro di dove sia il problema ... – Mehrdad

+7

Ora fallisce, non fallirebbe se fosse consentito legarsi ad un temporaneo. L'int viene convertito in un doppio temporaneo prima di essere passato alla funzione. –

+2

Hmm, interessante ... ma non potevano dire "se il valore è già un riferimento a valore-l, non sono consentite conversioni implicite a un altro tipo di riferimento di valore l"? O forse questo avrebbe sconfitto il punto ... non è sicuro, continuando a pensarci ... +1 – Mehrdad

2

C'è una ragione logica per questo. Pensa, cosa vuoi in questa riga:

String& a = String("test");   // Error 

Vuoi un riferimento. Un riferimento si riferisce all'oggetto a cui fa riferimento. Come un indirizzo dell'oggetto (sebbene i riferimenti non siano indirizzi, rende la spiegazione più chiara in questo modo).In realtà provi a ottenere qualcosa come un indirizzo di String("test"). Ma quell'oggetto svanirà proprio sulla riga successiva, quindi qual è il punto del suo indirizzo, se l'oggetto a cui punta non esiste? a ora punta a qualcosa di insignificante ...

Per quanto riguarda la seconda domanda, qual è il punto di consentire tutti gli oggetti temporanei complessivamente, beh, non c'è niente di sbagliato in questo. Si consideri, ad esempio, il caso in cui si desidera passare un oggetto String a una funzione, che restituisce, ad esempio, una stringa modificata corrispondente a tale stringa. Chiamiamo la funzione DoubleString, così invece di fare

String s("hello "); 
String s2 = DoubleString(s); 

È possibile utilizzare una più breve, più conveniente forma

String s2 = DoubleString(String("hello ")); 

Sede, l'oggetto temporaneo String("hello ") sopravvive l'intera riga di codice, che significa che è intatto quando inviato a DoubleString e dopo di esso. Viene distrutto solo quando l'intera linea è finita.

8

Se C++, è così acuto a bloccare modificando gli oggetti temporanei, avrebbe dovuto bloccato lettura degli oggetti temporanei giusto? Se l'oggetto temporaneo è sparito, non ha senso leggere i contenuti da lì giusto?

No, leggere l'oggetto è perfettamente ragionevole. Solo perché sta per svanire in futuro non significa leggere i dati ora è inutile.

open_file(std::string("foo.txt")); 

std::string("foo.txt") è una temporanea che si fermerà esistente dopo la chiamata a open_file() ma i dati in esso contenuti, mentre esiste questioni molto.

Il razionale per non consentire i vincoli temporali ai riferimenti non costanti non è in realtà un problema fondamentale con la scrittura nei provvisori. Infatti in molti luoghi C++ è perfettamente felice di consentire provvisori da modificare:

std::string("foo") = "bar"; 

E 'solo che i progettisti hanno ritenuto che avrebbe causato un numero sufficiente di problemi (probabilmente a causa del linguaggio comune di 'parametri out') senza abilitare nulla di simile valore, quindi hanno semplicemente preso una decisione progettuale per vietare i vincoli temporali ai riferimenti non const.

Con riferimenti rvalue ora si può fare esattamente ciò che è stato proibito prima:

void foo(int &&output) { 
    output = 1; 
} 

foo(2); 

Questo funziona bene, non solo è molto utile.

+5

"Il razionale per non permettere che i temporari si leghino a riferimenti non costanti non è in realtà un problema fondamentale con la scrittura nei provvisori" - grazie per averlo menzionato. – rekli