2016-04-25 38 views
7

Ho effettuato il porting di un codice legacy da win32 a win64. Non perché la dimensione dell'oggetto win32 fosse troppo piccola per le nostre esigenze, ma solo perché win64 ora è più standard e desideriamo portare tutti i nostri ambienti in questo formato (e usiamo anche alcune librerie di terze parti che offrono prestazioni migliori a 64 bit rispetto a 32 bit) .Qual è la migliore strategia per sbarazzarsi di "avviso C4267 possibile perdita di dati"?

Finiamo con tonnellate di;

C4267 avvertimento: 'argomento': conversione da 'size_t' per '...', possibile perdita di dati

Principalmente a causa di un codice simile: unsigned int size = v.size(); dove v è un contenitore STL.

So perché l'avviso ha senso, so perché viene emesso e come potrebbe essere risolto. Tuttavia, in questo esempio specifico, non abbiamo mai riscontrato casi in cui la dimensione del contenitore ha superato il valore massimo di unsigned int nel passato .... quindi non ci sarà alcun motivo per cui questo problema venga visualizzato quando il codice viene portato nell'ambiente a 64 bit.

Abbiamo discusso su quale sarebbe la migliore strategia per sopprimere quegli avvertimenti rumorosi (potrebbero nasconderne uno rilevante che mancherà), ma non siamo riusciti a prendere una decisione sulla strategia appropriata.

Quindi sto ponendo la domanda qui, quale sarebbe la migliore strategia consigliata?

1. Usare un static_cast

Utilizzare un static_cast. Do unsigned int size = static_cast<unsigned int>(v.size());. Non mi piace "questo" perché perdiamo la capacità di 64 bit di memorizzare un'enorme quantità di dati in un contenitore. Ma, come il nostro codice non ha mai raggiunto il limite 32bit, quindi questo sembra essere una soluzione sicura ...

2. Sostituire unsigned int da size_t

che è sicuramente più difficile, come unsigned int size oggetto nell'esempio di cui sopra potrebbe essere pased ad altre funzioni, salvato come attributo di classe e poi la rimozione di un avvertimento di una riga potrebbe finire a fare centinaia di modifica del codice ...

3. disattivare l'avviso

che è più probabile che una pessima idea in quanto sarebbe anche disabilitare gli avvisi in questo caso uint8_t size = v.size() che è sicuramente probabile che a causare la perdita di dati ....

4. Definire una "fusione sicura" * la funzione e lo usano

Qualcosa like:

template <typename From, typename To> To safe_cast(const From& value) 
{ 
    //assert(value < std::numeric_limits<To>::max() && value > std::numeric_limits<To>::min()); 
    // Edit 19/05: test above fails in some unsigned to signed cast (int64_t to uint32_t), test below is better: 
    assert(value == static_cast<From>(static_cast<To>(value))); // verify we don't loose information! 
    // or throw.... 
    return static_cast<To>(value); 
} 

5. Altre soluzioni sono i benvenuti ...

"Utilizzare la soluzione 1 in questo caso ma 2 in questo caso" potrebbe essere una buona risposta.

+3

L'utilizzo di '' 'size_t''' sarebbe stata la soluzione corretta direttamente dall'inizio. Lo farei anche io e mentre lo stai facendo, usa '' 'size_t''' correttamente alla fine. –

+0

@JanHenke: vero. Questo è in realtà il vantaggio della soluzione 2 ... il problema verrà risolto per sempre ...anche quando passeremo a win128 ;-) Ma è così doloroso aggiornare tutto il codice .... – jpo38

+0

@JanHenke: No, è troppo semplice da dire. Ho sempre lo stesso avviso, ad es. da fare una FFT su dati audio. Fidati di me, non avrò mai cornici audio della durata di 27 ore, con una risoluzione di frequenza di 10 uhz. La risoluzione di 0,7 Hz (44 kHz/65536) è già quasi perfetta. Quindi, dovrei rinunciare alla memorizzazione dei miei risultati FFT in 'std :: vector'? No, anche per le collezioni che sono rigorosamente più piccole di 64K elementi, il vettore è ancora la scelta migliore. – MSalters

risposta

8

Usa il tipo corretto (opzione 2) - la funzione/l'interfaccia definisce quel tipo per te, usalo.

std::size_t size = v.size(); // given vector<>::size_type is size_t 
// or a more verbose 
decltype(v)::size_type size = v.size(); 

Va a l'intento ... hai trovato la size di v e che size ha un tipo. Se il tipo corretto fosse stato utilizzato dall'inizio, questo non sarebbe stato un problema.

Se si richiede tale valore successivamente come un altro tipo, trasformarlo; il safe_cast<> è quindi una buona alternativa che include il controllo dei limiti di runtime.

Opzione 6. Utilizzare auto

Quando si utilizza size = v.size(), se non si è preoccupato di che tipo è, ma solo che si utilizza il tipo corretto,

auto size = v.size(); 

E lasciare che il compilatore fare il duro lavoro per te.

+0

defenitly auto è la strada da percorrere, perché essere masochista e usare altri modi? –

+0

@DavidHaim. Sì, vorrei andare con 'auto'. L'opzione 2 sarebbe la migliore di quelle che sta già considerando, ma 'auto' è più facile (IMO). – Niall

+0

Grazie per questa opzione di 6. Ma una parte del nostro codice è ancora compilata in 32 bit con vecchi compilatori che non supportano C++ 11 (ci colleghiamo con file .lib di terze parti disponibili solo in 32 bit) ..... avremo bisogno di risolverlo anche un giorno .... ;-) – jpo38

-1

IFF hai la pressione di tempo per ottenere il codice di avvertimento libera, avrei inizialmente disattivare l'avviso - il codice utilizzato per lavorare con questo, ed è, secondo me, estremamente improbabile che nei casi in cui si assegna a 32 bit lo supererai. (4 G valori in una collezione - dubito che volerò in applicazioni normali.)

Detto questo, per i casi altro di collezioni, l'avviso ha certamente il merito, in modo da cercare di ottenere ha permesso prima o più tardi.

In secondo luogo, quando le consente e che fissa il codice, mia la precedenza sarebbe:

  • Usa auto (o size_t pre C++ 11) per i locali in cui il valore non viene ulteriormente ridotto.
  • Per quando è necessario il restringimento, utilizzare safe_cast se si può giustificare il sovraccarico dell'introduzione alla propria squadra. (Apprendimento, di esecuzione, ecc)
  • Altrimenti basta usare static_cast:

    non credo che questo sia un problema con le collezioni. Se è non sa meglio il contrario, la tua collezione non avrà mai più più di 4G articoli. IMHO, non ha senso avere tanti dati in una collezione per i normali casi d'uso del mondo reale. (Questo non vuol dire che potrebbe non esserci il caso strano in cui avrai bisogno di set di dati così grandi, è solo che saprai quando questo è il caso.)

    Per i casi in cui in realtà non si restringe un Conta di una collezione, ma alcuni altri numerici, il restringimento è probabilmente problematico in ogni caso, quindi il problema verrà risolto in modo appropriato.