unique_ptr shared_ptr pointer make_shared example c++ templates c++11 shared-ptr

c++ - pointer - shared_ptr example



Usando shared_from_this en clases con plantillas (3)

Tengo un administrador de recursos que, como Andrei Alexandrescu propuso en el libro Modern C ++ Design, sigue un diseño basado en políticas. Sin embargo, estoy teniendo problemas, porque mi administrador de recursos necesita poder proporcionar referencias a sí mismo de los recursos administrados por shared_from_this() .

Construí un ejemplo mínimo reproduciendo mi problema, cuyos resultados puede ver here .

Básicamente tengo algún recurso gestionado que necesita una referencia a su gerente:

template <typename T> class managed_resource { typedef std::shared_ptr<manager<T>> manager_ptr; public: managed_resource(manager_ptr const & parent) : parent_(parent) { } /* ... */ private: manager_ptr parent_; };

Y un gerente que almacena y proporciona recursos:

template <typename Policy> class manager : Policy , std::enable_shared_from_this<manager<Policy>> { typedef managed_resource<Policy> resource; typedef std::shared_ptr<resource> 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<resource>(shared_from_this()); p.store(name, res); return res; } };

Como puede ver, el almacenamiento en sí está basado en políticas. Mientras que el administrador crea los recursos, la política puede decidir libremente entre varios enfoques para almacenar la información (por ejemplo, podría elegir no almacenar nada y crear nuevos recursos cada vez).

Este es un ejemplo de una política de almacenamiento:

class map_policy { typedef std::shared_ptr<managed_resource<map_policy>> resource_ptr; typedef std::map<std::string, resource_ptr> 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_; };

Pero me sale un error de compilación:

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<manager<map_policy> >’ is an inaccessible base of ‘manager<map_policy>’

Para la salida de compilación completa vea el here .

¿Es imposible usar std::enable_shared_from_this y shared_from_this() dentro del diseño basado en políticas? Si no, ¿cuál es la forma correcta de usarlo?


Como otros han escrito, debes usar this->shared_from_this() . Pero realmente no ayuda . He editado tu código aún más y he hecho todo público (todas las classes como structs y no public , private , ...). Ahora se compiles . A veces es mejor no pensar en limitar el acceso a los miembros al hacer prototipos (ya que puede dar lugar a más errores de compilación). Esto se puede hacer más tarde cuando las pruebas están bien.


El compilador le está diciendo que el problema es la búsqueda de nombres dependientes frente a la búsqueda de nombres no dependientes. "Dependiente" significa "depende de un parámetro de plantilla".

Los nombres no dependientes se buscan cuando la definición de la plantilla se analiza (primero), mientras que los nombres dependientes (y sus miembros) solo se buscan cuando se crea una instancia de la plantilla.

En su caso, el nombre shared_from_this no depende de ningún parámetro de plantilla, por lo que el compilador desea acceder a él cuando analiza la plantilla. Sin embargo, su clase lo obtiene de enable_shared_from_this<manager<Policy>> , que depende de un parámetro de plantilla, por lo que solo se analiza el tiempo de creación de instancias.

Debe convertir shared_from_this en un nombre dependiente. Tienes dos opciones:

  1. Calificarlo con algo dependiente. Lo más fácil es usar this->shared_from_this() .

  2. Póngalo en el ámbito explícitamente, poniendo una declaración de uso en su definición de clase: using std::enable_shared_from_this<manager<Policy>>::shared_from_this;


enable_shared_from_this<manager<Policy>> es una "base dependiente" (es una clase base cuyo tipo depende de un parámetro de plantilla, en este caso Policy ), por lo que las reglas de C ++ dicen que la búsqueda de nombres no calificados no se ve allí, es necesario para decir this->shared_from_this() o std::enable_shared_from_this<manage<Policy>>::shared_from_this() para encontrar el miembro de la base dependiente.

Consulte http://gcc.gnu.org/wiki/VerboseDiagnostics#dependent_base para obtener más detalles y enlaces a otras referencias.

Para corregir el segundo error, debe hacer que enable_shared_from_this una clase base pública , o no se puede inicializar cuando el administrador es propiedad de shared_ptr .