web-dev-qa-db-fra.com

std :: set, comment fonctionnent lower_bound et upper_bound?

J'ai ce simple morceau de code:

#include <iostream>
#include <set>

using std::set;

int main(int argc, char argv) {
   set<int> myset;
   set<int>::iterator it_l, it_u;
   myset.insert(10);
   it_l = myset.lower_bound(11);
   it_u = myset.upper_bound(9);

   std::cout << *it_l << " " << *it_u << std::endl;
}

Ceci affiche 1 comme limite inférieure pour 11 et 10 comme limite supérieure pour 9.

Je ne comprends pas pourquoi 1 est imprimé. J'espérais utiliser ces deux méthodes pour obtenir une plage de valeurs pour une limite supérieure/inférieure donnée.

8
user8469759

De cppreference.com on std :: set :: lower_bound :

Valeur de retour

Itérateur pointant sur le premier élément qui n'est pas moins clé. Si aucun élément de ce type n'est trouvé, un itérateur passé-la-fin (voir end () ) est renvoyé.

Dans votre cas, étant donné que votre ensemble ne contient aucun élément qui ne soit inférieur (c'est-à-dire supérieur ou égal à 11), un itérateur de la fin du dernier est renvoyé et affecté à it_l. Puis dans votre ligne:

std::cout << *it_l << " " << *it_u << std::endl;

it_l: ce comportement est indéfini et peut entraîner n'importe quoi (1 dans votre test, 0 ou toute autre valeur avec un autre compilateur, ou le programme peut même tomber en panne).

Votre limite inférieure doit être inférieure ou égale à la limite supérieure et vous ne devez pas déréférencer les itérateurs en dehors d'une boucle ou de tout autre environnement testé:

#include <iostream>
#include <set>

using std::set;

int main(int argc, char argv) {
   set<int> myset;
   set<int>::iterator it_l, it_u;
   myset.insert(9);
   myset.insert(10);
   myset.insert(11);
   it_l = myset.lower_bound(10);
   it_u = myset.upper_bound(10);

    while(it_l != it_u)
    {
        std::cout << *it_l << std::endl; // will only print 10
        it_l++;
    }
}
5
wasthishelpful

C'est UB. Votre it_l = myset.lower_bound(11); renvoie myset.end() (car il ne trouve rien dans l'ensemble), ce que vous ne vérifiez pas, puis vous imprimez essentiellement la valeur de l'itérateur passé-the-end.

3
SingerOfTheFall

Le lower_bound () renvoie l'itérateur au premier élément qui est pas moins qu'une clé. Lorsque cet élément n'est pas trouvé, la fin () est renvoyée.

Notez que l'itérateur est retourné avec end () pointe sur l'élément qui est passé-la-fin dans la collection. Ceci est un comportement normal des conteneurs standard pour indiquer que quelque chose s'est mal passé. En règle générale, vous devriez toujours vérifier cela et agir en conséquence.

Votre morceau de code est l'exemple de la situation ci-dessus car il n'y a pas d'éléments qui ne sont pas inférieurs à 11 dans l'ensemble. Le '1' imprimé est simplement une valeur de mémoire provenant de l'itérateur end ().

Voyez-le par vous-même avec l'extrait suivant:

#include <iostream>
#include <set>

using std::set;

int main(int argc, char argv) {
   set<int> myset;
   set<int>::iterator it_l, it_u;
   myset.insert(10);

   it_l = myset.lower_bound(11);
   if (it_l == myset.end()) {
       std::cout << "we are at the end" << std::endl;
   }

   it_u = myset.upper_bound(9);

   std::cout << *it_l << " " << *it_u << std::endl;
}
2