2010-07-12 9 views
5

Il seguente segmento dimostra il mio problema: (errore di compilazione su GCC)domanda sull'uso stringa :: swap() con temporanei

stringstream ss; 
string s; 
ss << "Hello"; 

// This fails: 
// s.swap(ss.str()); 

// This works: 
ss.str().swap(s); 

mio errore:

constSwap.cc:14: error: no matching function for call to 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >::swap(std::basic_string<char, std::char_traits<char>, std::allocator<char> >)' 
basic_string.tcc:496: note: candidates are: void std::basic_string<_CharT, _Traits, _Alloc>::swap(std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 

Mentre capisco che str () in stringstream restituisce un temporaneo, non ha senso e non era immediatamente evidente che avrei dovuto chiamare lo swap sul temporaneo con la variabile locale come parametro invece del mio primo istinto.

Ovviamente l'assegnazione diretta funziona meglio e gli standard C++ più recenti hanno una semantica che è perfetta, ma questi non sono disponibili per la mia implementazione.

Visual Studio non fornisce questo problema poiché è rilassato rispetto allo standard C++. Ho già compreso l'intero riferimento const a una cosa temporanea (che presumo sia la ragione dei miei errori di compilazione).

La mia domanda: Qualcuno può spiegarmi se questa è l'unica soluzione e forse spiegarmi come pensarlo in futuro in modo da poter individuare e risolvere problemi simili?

(Se nessuno ha qualche grandi intuizioni sto almeno distacco questo qui per le persone con problemi simili)

+0

Un'altra nota, perché uno scambio funzioni deve passare in un riferimento non const. E tutto quello che ho è (dato che è un ritorno temporaneo) un constvalore. Quindi capisco ... non ha immediatamente senso logico che il contrario sia legale (anche se capisco perché lo sia anche). – Marius

+1

Stai compilando il codice in VS2010, ha 2 varianti di swap. Uno prende riferimento e l'altro riferimento di valore. Questo potrebbe essere il motivo per cui sta compilando. – Jagannath

+0

@Jagannath: Sto usando VS2005 al momento, quindi ahimè, nessuna di queste nuove tecniche sono disponibili per me. – Marius

risposta

2

Dopo aver usato lo swap-con-temporanei abbastanza volte idioma, con linee come

std::vector<int>().swap(v); // clear and minimize capacity 

o

std::vector<int>(v).swap(v); // shrink to fit 

questo non sembra così fuori luogo. È normale per chiamare lo swap come una funzione membro di un oggetto temporaneo. Naturalmente, non è così idiomatico usare lo swap per compilare una stringa costruita di default invece di usare un costruttore di copia, come già accennato.

+0

Questo meglio ha indirizzato la mia domanda. Credo che dovrei solo abituarmi all'idioma. – Marius

7

Non si può associare un temporaneo per un riferimento non-const. Per questo motivo il temporaneo restituito da ss.str() non può essere passato a std::string::swap che si aspetta di modificare il suo parametro (quindi prende il suo argomento usando non-const&).

La seconda versione funziona come si chiama una funzione membro sull'oggetto temporaneo che è consentito.

Ma perché vuoi scambiare il primo posto? Normalmente, un semplice:

std::string s(ss.str()); 

dovrebbe essere sufficiente. Questo non è meno efficiente dello swap (almeno in C++ 0x con semantica di movimento), ma allo stesso tempo molto più leggibile.

+0

+1 per la digitazione più veloce di me. – Cogwheel

+0

'std :: string s (s.str())' è più lento dello scambio, perché deve copiare la stringa (eccetto in C++ 0x che ha semantica di spostamento usando i riferimenti '&&'). –

+0

Hai certamente ragione, ho modificato la mia risposta di conseguenza. – hkaiser

1

Il motivo per cui non è possibile passare l'argomento temporaneo come swap è che l'argomento viene passato dal riferimento non const. E i temporari possono essere vincolati solo da riferimenti costanti. Questo si sviluppa su §8.5.3, con l'essere adeguata al paragrafo 5, secondo punto:

§8.5.3 A reference to type “cv1 T1” is initialized by an expression of type “cv2 T2” as follows:

  • [bullet one, does not apply here: binding to non-const ref ]

  • Otherwise, the reference shall be to a non-volatile const type (i.e., cv1 shall be const).

Il motivo per cui la scrittura della chiamata nella direzione opposta funziona è che lo standard permette di chiamare mutare le funzioni membro su temporanea oggetti.

§3.10/10 An lvalue for an object is necessary in order to modify the object except that an rvalue of class type can also be used to modify its referent under certain circumstances. [Example: a member function called for an object (9.3) can modify the object. ]

La linea di ragionamento che è richiesta per il futuro è che, mentre è possibile modificare una temporanea attraverso le sue proprie funzioni, non è possibile passare ad una funzione o metodo che potrebbe modificarlo (passano da non-const riferimento)