Bonjour à tous,

J'ai un doute sur une implémentation. Quel est le meilleur moyen de retourner un conteneur de pointeurs d'objets de façon à ce que les objets ne puissent pas être accédés de façon non-const ?

Soit une classe « panier » contenant une liste d'objets de type « pomme ».
De façon naïve, on commence par écrire le code suivant :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
#include <list>
 
class pomme
{
    public:
        void
        set_taille(int){/*...*/};
 
    //...
};
 
class panier
{
    public:
        //...
 
        const std::list<pomme*>&
        get_pommes() const
        {
            return pommes_;
        }
 
    private:
        std::list<pomme*> pommes_;
};
Or, de cette façon, rien ne nous empêche d'appeler une méthode non-const d'un des objets pomme du conteneur (ce qui est tout à fait logique, mais totalement indésirable) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
 
void
foo(const panier& un_panier)
{
    const std::list<pomme*>& pommes = un_panier.get_pommes();
    if(!pommes.empty()) pommes.back()->set_taille(3);
}

Quelle est la bonne façon de faire dans un tel cas de figure ?
Il y a trois méthodes qui me viennent à l'esprit :
  1. ne pas écrire d'accesseur direct à la liste, mais interfacer son accès via un itérateur qui renverra des const pomme* const ;
  2. gérer deux listes : une contenant des pomme* et une autre des const pomme* ;
  3. modifier l'accesseur à la liste de façon à ce qu'il retourne un objet proxy encapsulant la liste et proposant une interface empêchant une modification des objets pointés (probablement à base d'itérateur similaire à la première méthode).


La méthode 1 induit l'écriture d'un tas de méthodes membres (get_pommes_begin_iterator(), _end_iterator(), sans parler d'empty() et de size()), ce qui serait extrêmement lourd).
La méthode 2 me semble être la plus simple à mettre en place.
La méthode 3 semble propre elle aussi (quoique je n'ai pas énormément creusé cette possibilité), mais si elle était généralement utilisée on aurait des classes proxy template déjà présentes dans la STL ou dans Boost, mais il n'y existe rien de tel à ma connaissance.

Si je devais faire un choix moi-même, ce serait donc la méthode 2.
Toutefois, j'aimerais beaucoup avoir vos différents avis. Utilisez-vous une autre méthode à laquelle je n'ai pas pensée ?

J'attends vos réponses