2010-08-10 4 views
1

Envisagez le programme suivant. Il crée un ensemble de pointeurs sur les valeurs et utilise un comparateur indrect_less personnalisé qui trie l'ensemble par la valeur de l'entier pointé. Une fois cela fait, je change ensuite la valeur de l'un des entiers pointés. Ensuite, on peut voir que l'ordre de l'ensemble n'est plus trié (je suppose que l'ensemble ne sait pas que quelque chose a changé).Invalidation d'un ensemble de pointeurs via l'indirection

(Ne prêtez pas attention C++ 0x boucles, je suis en cours d'exécution sur VS2010)

#include <iostream> 
#include <set> 
using namespace std; 

struct indirect_less { 
    bool operator()(int* l, int* r) const 
    { 
     return *l < *r; 
    } 
}; 

int main() 
{ 
    set<int*, indirect_less> myset; 

    int* a = new int(5); 
    int* b = new int(6); 
    int* c = new int(7); 

    myset.insert(a); 
    myset.insert(b); 
    myset.insert(c); 

    cout << "Set contains: "; 
    // (outputs: 5 6 7) 

    for (auto i = myset.begin(), end = myset.end(); i != end; ++i) 
    { 
     cout << **i << " "; 
    } 

    cout << endl << "Modifying *a" << endl; 
    *a = 9;   // point of interest 
    cout << "Set contains: "; 
    // (outputs: 9 6 7 - unsorted order) 

    for (auto i = myset.begin(), end = myset.end(); i != end; ++i) 
    { 
     cout << **i << " "; 
    } 

    cout << endl; 

    cin.get(); 

    return 0; 
} 

1) Ai-je raison que j'invoque un comportement non défini? L'état complet de myset est-il invalide après la ligne *a = 9;?

2) Est-ce la seule façon correcte d'effacer, puis de réinsérer a?

3) Est-il possible, une fois que *a = 9; a été exécuté, de rééquilibrer l'ensemble dans un ordre trié, avec un comportement bien défini?

+1

Je choisirai Oui, Oui, Non. –

+0

Est-ce qu'un comportement est défini après cette ligne? Pourriez-vous sûrement itérer sur l'ensemble (avec un ordre indéfini) par exemple? – AshleysBrain

+0

Undefined ne fonctionne pas de cette façon. Une fois que vous invoquez un comportement indéfini, tous les paris sont désactivés. Votre programme peut faire n'importe quoi, y compris semblant continuer à travailler. Jusqu'à ce que non. Habituellement lors de la démonstration du code pour quelqu'un d'important. – KeithB

Répondre

2

Oui, std::set suppose que les éléments sont immuables. C'est possible, si dangereux, de le réordonner après chaque changement. Je ne le recommanderais pas, cependant: utilisez un autre type de collection.

1

1) Oui, l'ensemble n'autorise pas la modification de ses éléments.

2) Outre la suppression de l'ancienne valeur et l'insertion de la nouvelle valeur, vous pouvez également remplacer l'ancien par un nouveau.

3) Non

1

1) Je ne sais pas que le comportement est indéfini. La torsion supplémentaire dans cet exemple est que les éléments de l'ensemble ne sont pas modifiés - chaque élément de l'ensemble est un pointeur. Si vous deviez imprimer les éléments (pointeurs) de l'ensemble avant et après l'exécution de la ligne '* a = 9', je crois que vous constateriez que les valeurs du pointeur sont dans le même ordre avant et après l'affectation. la valeur que pointe un élément de jeu. Cela a eu lieu en dehors des auspices de l'ensemble, et donc l'ensemble n'a aucun moyen de maintenir l'ordre que vous désirez

2) Un «oui» qualifié. indirect_less() pour ordonner les éléments de l'ensemble Encore une fois, sachez que vous commandez les éléments de l'ensemble, pointeurs, par la valeur de chaque pointeur déréférencé, mais cela me semble quelque peu risqué, exactement pour la raison que vous décrivez De la légende "Set contient:" dans la sortie imprimée, je présume que cet exemple s trives pour former un ensemble d'entiers. Cependant, l'ensemble défini, c'est-à-dire "set", consiste en fait en des pointeurs en nombres entiers, et non en des entiers eux-mêmes. Je crois que ce désalignement entre les collections désirées et réelles est la cause sous-jacente du problème.

3) Voir 2).

Questions connexes