89 votes

Comment dois-je traiter avec "signé/non signé" incompatibilité de mises en garde (C4018)?

Je travaille avec beaucoup de code de calcul écrit en C++ avec la haute performance et faible surcharge de la mémoire à l'esprit. Il utilise des conteneurs STL (surtout vector) beaucoup, et parcourt que les conteneurs presque dans chaque fonction.

L'itération du code ressemble à ceci:

for (int i = 0; i < things.size(); ++i)
{
    // ...
}

mais il produit de l' signé/non signé incompatibilité d'avertissement (C4018 dans Visual Studio).

Remplacement d' int certains unsigned type est un problème parce que nous avons souvent l'utilisation d'OpenMP pragmas, et il faut le compteur int.

Je suis sur le point de supprimer les (centaines de) mises en garde, mais j'ai peur, j'ai perdu un peu de solution élégante à ce problème.

Sur les itérateurs. Je pense que les itérateurs sont grands lorsqu'il est appliqué dans les endroits appropriés. Le code que j'ai travaille avec la volonté de ne jamais changer d'accès aléatoire conteneurs en list ou quelque chose (donc itération avec des int i est déjà conteneur agnostique), et aura toujours besoin de l'index en cours. Et le code que vous avez besoin de type (itérateur lui-même et l'index) juste complique les choses et dissimule la simplicité du code sous-jacent.

13voto

ereOn Points 18624

Idéalement, je voudrais utiliser une construction comme ceci à la place:

for (std::vector<your_type>::const_iterator i = things.begin(); i != things.end(); ++i)
{
  // if you ever need the distance, you may call std::distance
  // it won't cause any overhead because the compiler will likely optimize the call
  size_t distance = std::distance(things.begin(), i);
}

Cela a un très net avantage que votre code devient tout à coup un conteneur agnostique.

Et en ce qui concerne votre problème, si certains de bibliothèque que vous utilisez exige l'utilisation d' intunsigned int serait un meilleur ajustement, de leur API est en désordre. De toute façon, si vous êtes certain que ceux - int sont toujours positifs, vous pouvez simplement faire:

int int_distance = static_cast<int>(distance);

Qui permettra de préciser clairement votre intention de le compilateur: il ne sera pas vous embêter avec des avertissements plus.

11voto

Adrian McCarthy Points 17018

Si vous ne pouvez pas/ne pas utiliser des itérateurs et si vous ne pouvez pas/ne pas utiliser std::size_t pour l'indice de boucle, faire un .size() de int la fonction de conversion des documents de l'hypothèse et de la conversion explicite silence l'avertissement du compilateur.

#include <cassert>
#include <cstddef>
#include <limits>

// When using int loop indexes, use size_as_int(container) instead of
// container.size() in order to document the inherent assumption that the size
// of the container can be represented by an int.
template <typename ContainerType>
/* constexpr */ int size_as_int(const ContainerType &c) {
    const auto size = c.size();  // if no auto, use `typename ContainerType::size_type`
    assert(size <= static_cast<std::size_t>(std::numeric_limits<int>::max()));
    return static_cast<int>(size);
}

Ensuite, vous écrivez votre boucle comme ceci:

for (int i = 0; i < size_as_int(things); ++i) { ... }

L'instanciation de ce modèle de fonction sera presque certainement être insérée. Dans les versions de débogage, l'hypothèse sera vérifiée. Dans les versions release, il ne sera pas et le code sera aussi rapide que si vous l'avez appelé size() directement. Ni la version produira un message d'avertissement du compilateur, et c'est une légère modification de la idiomatiques de la boucle.

Si vous voulez attraper l'hypothèse échecs dans la version ainsi, vous pouvez remplacer l'affirmation d'une instruction if qui jette quelque chose comme std::out_of_range("container size exceeds range of int").

Notez que cela résout à la fois le signed/unsigned de comparaison ainsi que la possibilité d' sizeof(int) != sizeof(Container::size_type) problème. Vous pouvez laisser tous vos messages d'avertissements activés et les utiliser pour attraper les vrais bugs dans d'autres parties de votre code.

0voto

Karthik_elan Points 24

J'ai eu un problème similaire. À l'aide de size_t ne fonctionnait pas. J'ai essayé l'autre qui a travaillé pour moi. (ci-dessous)

for(int i = things.size()-1;i>=0;i--)
{
 //...
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X