Quelle est la meilleure stratégie pour se débarrasser de “l’avertissement de perte possible de données C4267”?

J’ai porté un code hérité de win32 à win64. Non pas parce que la taille de l’object win32 était trop petite pour nos besoins, mais simplement parce que win64 est maintenant plus standard et que nous souhaitons porter tous nos environnements sur ce format .

Nous nous retrouvons avec des tonnes de;

warning C4267: ‘argument’: conversion de ‘size_t’ en ‘…’, perte éventuelle de données

Principalement à cause du code comme: unsigned int size = v.size();v est un conteneur STL.

Je sais pourquoi la mise en garde a du sens, je sais pourquoi elle est publiée et comment elle pourrait être corrigée. Cependant, dans cet exemple spécifique, nous n’avons jamais rencontré de cas où la taille du conteneur dépassait la valeur maximale de unsigned int dans le passé. Il n’y a donc aucune raison pour que ce problème apparaisse lorsque le code est porté sur un environnement 64 bits.

Nous avons discuté de la meilleure stratégie à adopter pour supprimer ces avertissements bruyants (ils peuvent cacher une stratégie pertinente qui nous manquera), mais nous ne pouvons pas prendre de décision sur la stratégie appropriée.

Donc, je pose la question ici, quelle serait la meilleure stratégie recommandée?

1. Utilisez un static_cast

Utilisez un static_cast . Do unsigned int size = static_cast(v.size()); . Je n’aime pas cela parce que nous perdons la capacité de 64 bits pour stocker une grande quantité de données dans un conteneur. Mais comme notre code n’a jamais atteint la limite des 32 bits, cela semble être une solution sûre …

2. Remplacez unsigned int par size_t

Cela est certainement plus difficile car l’object de unsigned int size dans l’exemple ci-dessus pourrait être passé à d’autres fonctions, enregistré en tant qu’atsortingbut de classe, puis supprimer un avertissement sur une ligne pourrait aboutir à des centaines de modifications de code …

3. Désactiver l’avertissement

C’est très probablement une très mauvaise idée car cela désactiverait également l’avertissement dans ce cas uint8_t size = v.size() qui risque de provoquer une perte de données ….

4. Définissez une fonction “cast sûr” * et utilisez-la

Quelque chose comme :

 template  To safe_cast( const From& value ) { //assert( value < std::numeric_limits::max() && value > std::numeric_limits::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(static_cast(value))); // verify we don't loose information! // or throw.... return static_cast( value ); } 

5. D’autres solutions sont les bienvenues …

“Utiliser la solution 1 dans ce cas mais 2 dans ce cas” pourrait parfaitement être une bonne réponse.

Utilisez le bon type (option 2) – la fonction / interface définit ce type pour vous, utilisez-le.

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

Cela va à l’intention … vous obtenez la size de v et cette size a un type. Si le type correct avait été utilisé depuis le début, cela n’aurait pas posé de problème.

Si vous avez besoin de cette valeur plus tard comme un autre type, transformez-la ensuite; the safe_cast<> est alors une bonne alternative qui inclut la vérification des limites d’exécution.

Option 6. Utiliser auto

Lorsque vous utilisez size = v.size() , si vous n’êtes pas concerné par le type, vous utilisez uniquement le type correct,

 auto size = v.size(); 

Et laissez le compilateur faire le travail difficile pour vous.

IFF vous avez du temps à mettre pour que le code prévienne gratuitement, je désactiverais d’ abord l’avertissement – votre code fonctionnait avec ceci, et il est, à mon humble avis, extrêmement improbable que dans les cas où vous atsortingbuez une taille de 32 bits il. (4 valeurs G dans une collection – je doute que cela va voler dans des applications normales.)

Cela étant dit, pour les cas autres que les collectes, l’avertissement a certainement du mérite, alors essayez de le faire activer tôt ou tard.

Deuxièmement, si vous l’activez et corrigez le code, ma priorité serait la suivante:

  • Utilisez auto (ou size_t pre C ++ 11) pour les sections locales où la valeur n’est pas réduite davantage.
  • Car si un rétrécissement est nécessaire, utilisez votre safe_cast si vous pouvez justifier le surcoût de le présenter à votre équipe. (apprentissage, application, etc.)
  • Sinon, utilisez simplement static_cast :

    Je ne pense pas que ce soit un problème avec les collections. Si vous ne savez pas le contraire, votre collection ne contiendra jamais plus d’articles 4G. IMHO, cela n’a tout simplement pas de sens d’avoir autant de données dans une collection pour tous les cas d’utilisation du monde réel normal. (Cela ne veut pas dire qu’il n’ya peut-être pas le cas étrange où vous aurez besoin de si grands ensembles de données, c’est juste que vous saurez quand c’est le cas.)

    Pour les cas où vous ne réduisez pas le nombre d’une collection, mais un autre nombre, le rétrécissement est probablement problématique de toute façon, alors vous corrigerez le code de manière appropriée.