2012-10-15 16 views
8

Sto cercando di fornire gli operatori ostream per alcune classi matematiche (matrice, vettore, ecc.) Un amico ha notato che l'implementazione della libreria standard gcc dell'operatore ostream per std::complex include l'uso interno di un flusso stringa per formattare l'output prima di passarlo al reale ostream:Uso di stringstream all'interno della funzione ostream

/// Insertion operator for complex values. 
template<typename _Tp, typename _CharT, class _Traits> 
    basic_ostream<_CharT, _Traits>& 
    operator<<(basic_ostream<_CharT, _Traits>& __os, const complex<_Tp>& __x) 
{ 
    basic_ostringstream<_CharT, _Traits> __s; 
    __s.flags(__os.flags()); 
    __s.imbue(__os.getloc()); 
    __s.precision(__os.precision()); 
    __s << '(' << __x.real() << ',' << __x.imag() << ')'; 
    return __os << __s.str(); 
} 

Questo modello è visibile in spinta pure. Stiamo cercando di determinare se questo è un modello che vale la pena seguire. È stato espresso il timore che includa un'intestazione aggiuntiva per il flusso di stringhe e che siano richieste allocazioni di heap aggiuntive all'interno del flusso di stringhe che potrebbero potenzialmente essere evitate.

La maggior parte ragionevolmente è stato suggerito che se il client richiede tale funzionalità, quindi possono creare il flusso di stringa e fare il pre-pass stessi.

Qualcuno può aiutarmi a capire perché questo sarebbe considerato una buona pratica e se dovrei adottarlo?

risposta

6

considerare che cosa succede se si imposta una larghezza di uscita sul ostream, quindi scrivere una std :: complesso ad esso - non si vuole la larghezza di influenzare solo l'operazione prima uscita (vale a dire il carattere '(')

std::complex i(0, 1); 
std::cout << std::setw(10) << std::left << i; 

Questo dovrebbe stampare "(0,1)     " non "(         0,1)"

formando l'intera produzione come una singola stringa, allora la scrittura fuori gli onori di uscita la larghezza del campo e le altre bandiere di formattazione impostate sul torrente.

2

Uno degli scopi principali di questo schema è evitare di conservare i manipolatori/flag del flusso originale e reimpostarli prima di tornare. Boost.IoStateSavers elimina la necessità di questo, quindi direi che l'utilizzo di detta libreria sarebbe una pratica migliore.

4

La ragione di thread citata in un'altra risposta non funzionerà molto: la stringa può ancora essere divisa sul livello del buffer del flusso perché queste operazioni non sono atomiche quando vengono chiamate da più thread.

Tuttavia, ci sono due considerazioni rilevanti:

  1. Per alcune uscite che si desidera modificare temporaneamente le impostazioni formato bandiera. Ad esempio, vuoi assicurarti che alcune stringhe appaiano usando la notazione esadecimale, per altre notazioni dec e vuoi ripristinare il flusso allo stato originale.
  2. Ancora più importante, il significato di width() di un output è il numero di caratteri che l'intera stringa di formattazione deve occupare almeno. Se si utilizzano gli operatori di output internamente a un altro operatore di output, il primo elemento occuperà la larghezza anziché l'intera stringa risultante costituita da più componenti. Ad esempio, per un numero complesso l'elemento reale occuperebbe width() anziché la combinazione dell'elemento reale, della virgola e dell'elemento immaginario.
Problemi correlati