34 votes

Utilisation de shared_from_this dans les classes modélisées

J'ai un gestionnaire de ressources qui, comme Andrei Alexandrescu l'a proposé dans le livre Modern C++ Design, suit une conception basée sur des politiques. Cependant, j'ai des problèmes, car mon gestionnaire de ressources doit être capable de fournir des références à lui-même aux ressources gérées par shared_from_this().

J'ai construit un exemple minimal reproduisant mon problème, dont vous pouvez voir les résultats ici.

Fondamentalement, j'ai des ressources gérées qui ont besoin d'une référence à leur gestionnaire:

template 
class managed_resource
{
        typedef std::shared_ptr> manager_ptr;
    public:
        managed_resource(manager_ptr const & parent)
            : parent_(parent)
        {
        }

        /* ... */

    private:
        manager_ptr parent_;
};

Et un gestionnaire qui stocke et fournit des ressources:

template 
class manager
    : Policy
    , std::enable_shared_from_this>
{
        typedef managed_resource resource;
        typedef std::shared_ptr resource_ptr;
    public:
        resource_ptr get_resource(std::string const & name)
        {
            Policy & p = *this;
            if(p.find(name))
            {
                return p.get(name);
            }
            resource_ptr res = std::make_shared(shared_from_this());
            p.store(name, res);
            return res;
        }
};

Comme vous pouvez le voir, le stockage lui-même est basé sur des politiques. Alors que le gestionnaire crée les ressources, la politique peut librement décider entre différentes approches de stockage de l'information (elle pourrait par exemple choisir de ne rien stocker et de créer de nouvelles ressources à chaque fois).

Voici un exemple d'une politique de stockage:

class map_policy
{
        typedef std::shared_ptr> resource_ptr;
        typedef std::map resources;

    public:
        bool find(std::string const & name)
        {
            resources::iterator res_it = resources_.find(name);
            return res_it != resources_.end();
        }

        resource_ptr get(std::string const & name)
        {
            resources::iterator res_it = resources_.find(name);
            return res_it->second;
        }

        void store(std::string const & name, resource_ptr const & res)
        {
            resources_[name] = res;
        }

    private:
        resources resources_;
};

Mais je reçois une erreur de compilation:

error: there are no arguments to ‘shared_from_this’ that depend 
       on a template parameter, so a declaration of 
       ‘shared_from_this’ must be available
error: ‘std::enable_shared_from_this >’ is 
       an inaccessible base of ‘manager’

Pour obtenir la sortie complète de la compilation, voir l'exemple minimal ici.

Est-il impossible d'utiliser std::enable_shared_from_this et shared_from_this() dans une conception basée sur des politiques? Si non, quelle est la manière appropriée de l'utiliser?

73voto

Jonathan Wakely Points 45593

enable_shared_from_this> est une "base dépendante" (c'est une classe de base dont le type dépend d'un paramètre de modèle, dans ce cas Policy) donc les règles de C++ disent que la recherche de nom non qualifié ne regarde pas dedans, vous devez dire this->shared_from_this() ou std::enable_shared_from_this>::shared_from_this() pour trouver le membre de la base dépendante.

Voir http://gcc.gnu.org/wiki/VerboseDiagnostics#dependent_base pour plus de détails et des liens vers d'autres références.

Pour corriger la deuxième erreur, vous devez faire de enable_shared_from_this une classe de base public, sinon elle ne peut pas être initialisée lorsque le gestionnaire est détenu par un shared_ptr.

4voto

Angew Points 53063

Le compilateur vous indique que le problème est lié à la recherche de noms dépendants par rapport à la recherche de noms non dépendants. "Dépendant" signifie "dépend d'un paramètre de modèle".

Les noms non dépendants sont recherchés lorsque la définition du modèle est (d'abord) analysée, tandis que les noms dépendants (et leurs membres) ne sont recherchés que lorsque le modèle est instancié.

Dans votre cas, le nom shared_from_this ne dépend d'aucun paramètre de modèle, c'est pourquoi le compilateur veut y accéder lors de l'analyse du modèle. Cependant, votre classe l'obtient de enable_shared_from_this>, qui dépend bel et bien d'un paramètre de modèle, et est donc recherché uniquement lors de l'instanciation.

Vous devez transformer shared_from_this en un nom dépendant. Vous avez deux options :

  1. Le qualifier avec quelque chose de dépendant. Le plus simple est d'utiliser this->shared_from_this().

  2. L'ajouter explicitement à la portée, en ajoutant une déclaration d'utilisation dans la définition de votre classe : using std::enable_shared_from_this>::shared_from_this;

-2voto

Jan Herrmann Points 1643

Comme d'autres l'ont écrit, vous devez utiliser this->shared_from_this(). Mais cela n'aide pas réellement. J'ai modifié votre code plus en détail et tout rendu public (toutes les classes comme des structs et aucun public, private, ...). Maintenant, cela compile. Parfois, il vaut mieux ne pas penser à limiter l'accès aux membres lors de la création de prototypes (car cela peut entraîner plus d'erreurs de compilation). Cela peut être fait plus tard une fois les tests validés.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X