2009-10-16 6 views
0

J'ai écrit ce programme, qui trie quelques ints en utilisant un foncteur:Fonctor C++ - comportement inattendu?

#include<iostream> 
#include<list> 
#include<set> 

using namespace std; 

struct IntSorter 
{ 
    unsigned int comparisons; 
    IntSorter() 
    { 
     std::cout << "new intsorter" << std::endl; 
     comparisons = 0; 
    } 

    bool operator() (const int &a, const int &b) 
    { 
     std::cout << "c is " << comparisons << std::endl; 
     ++comparisons; 
     std::cout << "c is now " << comparisons << std::endl; 
     return a<b; 
    } 
}; 

int main(int argc, char *argv[]) 
{  
    list<int> my_list; 
    my_list.push_back(4); 
    my_list.push_back(3); 
    my_list.push_back(5); 
    my_list.push_back(1); 

    IntSorter s; 
    my_list.sort(s); 

    for (list<int>::iterator it=my_list.begin(); it!=my_list.end(); it++) 
    { 
     std::cout << *it << std::endl; 
    } 

    return 0; 

} 

Le tri fonctionne très bien, mais la partie comptant le nombre de comparaisons donne un résultat que je ne m'y attendais pas:

./prog -a -b -c -d 
new intsorter 
c is 0 
c is now 1 
c is 0 
c is now 1 
c is 0 
c is now 1 
c is 1 
c is now 2 
c is 2 
c is now 3 
1 
3 
4 
5 

Je pensais que la structure serait réutilisée, en comptant et en stockant le nombre de comparaisons. Cependant, il semble de le copier, ou un autre comportement que les numéros imprimés vont 1,1,1,2,3, au lieu de 1,2,3,4,5. Qu'est-ce que je fais mal?

Répondre

2

Vous ne faites vraiment rien de mal. Le problème réside entièrement dans vos attentes - le trieur est passé en valeur, donc il y a un minimum d'une copie faite au fur et à mesure que vous le passez. La fonction de tri est également libre de faire plus de copies (par exemple, un tri récursif transmettra probablement une copie à chaque invocation récursive).

Il ya une leçon simple ici: un tel objet devrait être bon marché pour créer et/ou copier.

+1

Et pour le prouver, vous pouvez aussi la valeur de sortie de « ceci » dans l'opérateur() aussi bien. –

+0

C'est un bon point. –

3

Vous êtes sur la bonne voie. std :: list :: sort prend l'objet fonction par valeur. Comme il fait son travail, il passe une copie de votre objet de fonction autour de laquelle signifie que les données de membre de comparaisons sont également copiées.

Vous ne faites rien de mal, c'est juste que vous ne pouvez pas utiliser un foncteur comme celui-ci. La manière la plus simple de faire std :: list :: sort est d'incorporer une référence à un objet compteur externe dans votre foncteur. À chaque comparaison, transférez un appel à cet objet compteur. Après les retours de std :: list :: sort, vous aurez le total dedans.

0

Comme mentionner qu'il est passé par valeur: Une solution simple est:

struct IntSorter 
{ 
    unsigned int& comparisons; 
    IntSorter(unsigned int& c) 
     :comparisons(c) 
    {} 
    // Other Stuff 
}; 

// In main: 
unsigned int count = 0; 
my_list.sort(IntSorter(count)); 
Questions connexes