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.
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. –
@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
@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