J'itère sur un vecteur et j'ai besoin de l'index sur lequel l'itérateur pointe actuellement. AFAIK cela peut se faire de deux manières:
it - vec.begin()
std::distance(vec.begin(), it)
Quels sont les avantages et les inconvénients de ces méthodes?
c++
iterator
coding-style
cairol
la source
la source
it
?std::container_type::iterator it;
std::list
n'offre pas d'accès direct aux éléments par leur position, donc si vous ne pouvez pas le fairelist[5]
, vous ne devriez pas pouvoir le fairelist.begin() + 5
.Je préférerais
std::distance(vec.begin(), it)
car cela me permettra de changer le conteneur sans aucun changement de code. Par exemple, si vous décidez d'utiliserstd::list
au lieu de celuistd::vector
qui ne fournit pas d'itérateur d'accès aléatoire, votre code sera toujours compilé. Puisque std :: distance choisit la méthode optimale en fonction des traits de l'itérateur, vous n'aurez pas non plus de dégradation des performances.la source
vec
est une mauvaise nouvelle. Si le code a été réécrit pour être générique, en prenant le type de conteneur comme paramètre de modèle, c'est alors que nous pouvons (et devons) parler de la gestion des itérateurs à accès non aléatoire ;-)vec
est également une très mauvaise nouvelle.Comme l'ont montré UncleBens et Naveen, il y a de bonnes raisons pour les deux. Laquelle est "meilleure" dépend du comportement que vous souhaitez: voulez-vous garantir un comportement à temps constant, ou voulez-vous qu'il revienne au temps linéaire si nécessaire?
it - vec.begin()
prend un temps constant, maisoperator -
n'est défini que sur les itérateurs à accès aléatoire, de sorte que le code ne compilera pas du tout avec les itérateurs de liste, par exemple.std::distance(vec.begin(), it)
fonctionne pour tous les types d'itérateurs, mais ne sera une opération à temps constant que si elle est utilisée sur des itérateurs à accès aléatoire.Aucun des deux n'est "meilleur". Utilisez celui qui fait ce dont vous avez besoin.
la source
J'aime celui-ci:,
it - vec.begin()
parce que pour moi, il dit clairement "distance depuis le début". Avec les itérateurs, nous sommes habitués à penser en termes d'arithmétique, donc le-
signe est l'indicateur le plus clair ici.la source
distance
?it++
et pas quelque chose commestd::increment(it)
ça, non? Cela ne serait-il pas aussi moins clair?++
opérateur est défini dans le cadre des séquences STL comme la façon dont nous incrémentons l'itérateur.std::distance
calcule le nombre d'éléments entre le premier et le dernier élément. Le fait que l'-
opérateur travaille n'est qu'une coïncidence.Si votre algorithme est déjà limité / codé en dur pour utiliser un
std::vector::iterator
etstd::vector::iterator
seulement, peu importe la méthode que vous finirez par utiliser. Votre algorithme est déjà concrétisé au-delà du point où le choix de l'un peut faire la différence. Ils font tous les deux exactement la même chose. C'est juste une question de préférence personnelle. J'utiliserais personnellement une soustraction explicite.Si, d'autre part, vous souhaitez conserver un degré de généralité plus élevé dans votre algorithme, à savoir, pour permettre la possibilité qu'un jour à l'avenir, il puisse être appliqué à un autre type d'itérateur, la meilleure méthode dépend de votre intention. . Cela dépend de la façon dont vous souhaitez être restrictif en ce qui concerne le type d'itérateur qui peut être utilisé ici.
Si vous utilisez la soustraction explicite, votre algorithme sera limité à une classe d'itérateurs plutôt étroite: les itérateurs à accès aléatoire. (C'est ce que vous obtenez maintenant
std::vector
)Si vous utilisez
distance
, votre algorithme prendra en charge une classe beaucoup plus large d'itérateurs: les itérateurs d'entrée.Bien entendu, le calcul
distance
pour les itérateurs à accès non aléatoire est en général une opération inefficace (tandis que, pour les accès aléatoires, il est aussi efficace que la soustraction). C'est à vous de décider si votre algorithme a un sens pour les itérateurs à accès non aléatoire, en termes d'efficacité. Si la perte d'efficacité qui en résulte est dévastatrice au point de rendre votre algorithme complètement inutile, alors vous devriez mieux vous en tenir à la soustraction, interdisant ainsi les utilisations inefficaces et forçant l'utilisateur à rechercher des solutions alternatives pour d'autres types d'itérateurs. Si l'efficacité des itérateurs à accès non aléatoire est toujours dans la plage utilisable, vous devez utiliserdistance
et documenter le fait que l'algorithme fonctionne mieux avec les itérateurs à accès aléatoire.la source
Selon http://www.cplusplus.com/reference/std/iterator/distance/ , puisqu'il
vec.begin()
s'agit d'un itérateur à accès aléatoire , la méthode de la distance utilise l'-
opérateur.Donc, la réponse est, du point de vue des performances, c'est la même chose, mais peut-être que l'utilisation
distance()
est plus facile à comprendre si quelqu'un doit lire et comprendre votre code.la source
Je n'utiliserais la
-
variante que pourstd::vector
- c'est assez clair ce que l'on veut dire, et la simplicité de l'opération (qui n'est pas plus qu'une soustraction de pointeur) est exprimée par la syntaxe (distance
, de l'autre côté, sonne comme pythagore sur le première lecture, non?). Comme le souligne UncleBen,-
agit également comme une assertion statique en cas devector
modification accidentelle enlist
.Je pense aussi que c'est beaucoup plus courant - mais je n'ai pas de chiffres pour le prouver. Argument principal:
it - vec.begin()
est plus court dans le code source - moins de travail de frappe, moins d'espace consommé. Comme il est clair que la bonne réponse à votre question se résume à une question de goût, cela peut également être un argument valable.la source
Voici un exemple pour trouver "toutes" les occurrences de 10 avec l'index. Je pensais que cela serait d'une certaine aide.
la source