2016-01-27 19 views
6

Durante la migrazione di un'applicazione da VisualStudio 2005 a VisualStudio 2015 abbiamo rilevato un comportamento diverso in alcuni codici che concatenano le istanze CString quando tale codice viene creato con VS2015.
Quindi, ho creato una semplice applicazione console Win32 per dimostrare il problema.Comportamento diverso tra gli operatori CString "+ =" e "+"

L'applicazione console (utilizzando MFC come dll condiviso e set v'importa Unicode) esegue questa semplice funzione:

void f() 
{ 
    CString x('\0'); 

    CString r('a'); 
    r += x; 
    CString rr('a'); 
    rr = rr + x; 

    int rSize = r.GetLength(); 
    int rrSize = rr.GetLength(); 

    assert(rSize == rrSize); // This assert fires when compiled and run 
           // under Visual Studio 2015! 
} 

Essa mostra che, quando un CString contenente un carattere '\ 0' è concatenato ad un'altra istanza CString , usare '+ =' o usare '+' porta a risultati diversi!

Quando viene utilizzato '+ =', la dimensione del risultato viene calcolata contando tutti i caratteri fino al primo '\ 0' ... quindi la dimensione finale è 1!
Viceversa, quando si utilizza l'operatore '+', la dimensione CString del risultato è 2, ovvero la somma delle dimensioni delle istanze concatenate!

In VisualStudio 2005 la dimensione del risultato è sempre la somma delle dimensioni delle istanze concatenate!

I filed a bug a Microsoft poche settimane fa, ma fino ad ora non ho risposta da quei ragazzi.

Le mie domande:
1. Qualcuno si è imbattuto in questo bug nella libreria MCF ??
2. Come hai lavorato a questo bug? Stiamo pensando di vietare l'uso dell'operatore + = o di sostituire la classe CString con una classe personalizzata, ma tutto ciò mi sembra "un po '" invasivo.

+1

Solo FYI - lo stesso risultato su Visual Studio 2013. –

+0

Per curiosità, cosa succede quando si aggiunge a 'x' prima di aggiungere' x' alle altre stringhe? Mi piace 'x + =" Ciao, Mondo! ";'? –

+0

Il metodo 'Append()' di CString (usato nell'operatore '+ =') ha questo * strano * commento: '// Assicurarsi che non leggiamo la fine del terminazione di NULL', seguita da' nLength = StringLengthN (pszSrc , nLunghezza); '. Questo ** NON ** lascerà zero nel CString! –

risposta

6

La documentazione per la CStringT Class contiene la seguente dichiarazione criptica:

Anche se è possibile creare istanze CStringT che contengono caratteri null incorporati, si consiglia contro di essa. La chiamata di metodi e operatori su oggetti CStringT che contengono caratteri null incorporati può produrre risultati non previsti.

Francamente, non so davvero cosa fare della frase finale. Prendo come un avvertimento fare attenzione quando incorpori caratteri null. Indipendentemente da ciò, le garanzie contrattuali dovrebbero ancora valere quando lo fanno.

Analisi:

Questo a quanto pare non è il caso di CStringT::operator+=, però. Nel codice di esempio della questione l'attuazione operator+= richiama il sovraccarico

CSimpleStringT& operator+=(const CSimpleStringT& strSrc) 

, che modifica l'istanza corrente chiamando

void Append(const CSimpleStringT& strSrc) 

che a sua volta richiama

void Append(PCXSTR pszSrc, int nLength) 

passando un esplicito argomento di lunghezza. Questo dovrebbe essere sufficiente per gestire le stringhe in stile C con caratteri null incorporati.Stranamente, l'implementazione inizia quindi a indovinare l'input chiamando StringLengthN(pszSrc, nLength) (implementato come una chiamata a wcsnlen), per ricalcolare la lunghezza di pszSrc. Restituisce 0 per l'istanza CStringTx nel codice di esempio.

Risultato:

Per me, questo sembra essere un bug nell'implementazione. Per inciso, se si invertono gli argomenti su operator+= (ad esempio x += r; rispetto a r += x;), il risultato è una stringa di lunghezza 2, come previsto.

Risoluzione:

L'unica soluzione pulita sarebbe di avere Microsoft riconoscere il bug, e di fornire una correzione per esso. Non terrei il respiro, però, dato che Microsoft di solito non spedisce correzioni di errori, se cambiano il comportamento di un prodotto spedito.

Se non si riesce a convincere Microsoft a risolvere il bug, l'unica altra opzione è quella di non utilizzare l'operatore con un comportamento indesiderato. Un modo sarebbe utilizzare un'altra classe di stringa. Un sostituto ben consolidato è std::wstring, che è possibile convertire in un CStringW dove necessario (CStringW cstr(s.c_str(), s.length());).


Aggiornamento (2016/09/13):

L'OP ha presentato una defect report con Microsoft, e hanno riconosciuto il bug. È stata implementata una correzione di bug, ma "non verrà visualizzata fino alla prossima versione principale delle librerie (che potrebbe non essere necessariamente inclusa nell'attuale [2016-03-31] Visual Studio vNext)".

+0

Grazie @Ispectable per la tua risposta precisa. –

+0

In questi momenti stiamo valutando le nostre alternative per una soluzione a questo bug. Sfortunatamente la nostra applicazione super-legacy è piena di codice che potrebbe potenzialmente incontrare istanze CString che incorporano uno o più caratteri null e qualsiasi cosa scegliamo sarà un "bagno di sangue" !! ;) Grazie mille! –

+0

Penso che la "dichiarazione criptica" significhi "Possiamo implementarlo come vogliamo, quindi non contare su un risultato particolare." –