2010-07-28 6 views
4

J'ai un problème avec ce qui semble être une sorte de distribution implicite vers const lorsque j'utilise des itérateurs. Je ne suis pas vraiment sûr quel code est pertinent (si je l'ai fait je ne serais probablement pas poser cette question!) Alors je vais essayer de mon mieux pour illustrer mon problème.Les itérateurs STL et 'const'

typedef set<SmallObject> Container;    //not const 

void LargeObject::someFunction() {    //not const 
    Container::iterator it;      //not const 
    for (it = c.begin(); it != c.end(); ++it) { //assume c is a "Container" 
     (*it).smallObjectFunction();    //not a const function 
    } 
} 

Cependant je reçois toujours l'erreur suivante:

error: passing 'const SmallObject' as 'this' argument of 'int SmallObject::smallObjectFunction()' discards qualifiers 

Cependant, si je jetais comme ((SmallObject)(*it).smallObjectFunction(); puis-je me débarrasser du message d'erreur.

La seule chose que je peux comprendre est que en quelque sorte la définition de

bool operator< (const SmallObject &a) const; 

est en quelque sorte l'origine du iterator de retourner des objets const. Toute aide ou explication ici?

+0

Pourriez-vous publier l'implémentation de 'SmallObject'? – ULysses

Répondre

11

Les jeux et les cartes conservent les éléments dans l'ordre en fonction de la condition de tri. Pour que le code utilisateur ne casse pas les invariants, le key de la carte et l'élément entier de l'ensemble doivent être constants. Votre problème est que l'élément stocké n'est pas un SmallObject mais un const SmallObject.

Si cela était vous pourriez avoir ne se limite pas:

int init[] = { 1, 2, 3, 4, 5 }; 
std::set<int> values(init, init+5); 
std::copy(values.begin(), values.end(), 
    std::ostream_iterator<int>(std::cout, " ")); 
    // 1 2 3 4 5 
*(values.find(3)) = 5; // luckily this does not work! 
std::copy(values.begin(), values.end(), 
    std::ostream_iterator<int>(std::cout, " ")); 
    // 1 2 5 4 5 -- not in order!!! 

Le problème il n'y a pas seulement que maintenant l'élément de jeu ne serait pas dans l'ordre, mais selon la façon dont l'arbre a été construit il pourrait y avoir des éléments qui sont présents dans l'ensemble mais ne peuvent pas être trouvés.

+1

Donc, la création de la fonction smallObjectFunction const (si vous le pouvez) va résoudre le problème – Patrick

+0

Je modifie les objets dans certains cas de smallObjectFunction. Quelles sont mes options ici? Cast le comme je le mentionne (et fait actuellement)? Supprimer de l'ensemble, modifier et insérer de nouveau dans (moche)? Rien d'autre? – sas4740

+0

La bonne façon de le faire est de sortir le petit objet, de le modifier puis de l'insérer.Sinon, vous pouvez rompre l'ordre et les invariants dont 'set' dépend et vous obtiendrez des résultats inattendus. Si les changements n'affectent pas la commande, vous pouvez utiliser une carte avec la clé quelle qu'elle soit et modifier la valeur - ce n'est pas const. –

0

Les objets dans votre conteneur c sont const et smallObjectFunction essaie de modifier la valeur de l'objet.

3

Votre code est pas stupide et pourrait compiler proprement avec une mise en œuvre conforme STL, selon certaines décisions de conception que votre mise en œuvre du TSL fait. La norme C++ 03 ne précise pas ce que le référence typedef devrait être pour set :: iterators (à mon avis, ils devraient être des références non constantes). Donc continuer à faire ce que vous faites, mais insérez un const_cast:

const_cast<SmallObject&>(*it).smallObjectFunction(); 

Il est plus efficace et beaucoup plus claire que l'effacement et réinsérant. Pour une discussion plus approfondie de ce problème, consultez l'article 8 dans "C++ plus exceptionnel" par Herb Sutter.

Il est parfaitement sûr de faire un const_cast dans cette situation et ce n'est pas un mauvais style, assurez-vous de ne pas changer la valeur des champs qui déterminent la commande. Si l'interface de la classe rend difficile de vérifier que vous ne modifiez pas la commande, alors l'interface n'est probablement pas bien conçue.