videos una tips tema publico para oratoria hacer hablar forma exposiciones exposicion exponer cómo creativa como clase c++ c++11 unique-ptr ownership

c++ - una - videos de exposiciones



¿Cuál es la forma correcta de exponer los recursos que son propiedad de una clase? (7)

Como otros han respondido desde un punto de vista técnico, me gustaría señalarle un enfoque diferente y revisar su diseño. La idea es tratar de respetar la Ley de Demeter y no otorgar acceso a los subcomponentes del objeto. Es un poco más difícil de hacer, y sin un ejemplo específico no puedo proporcionar muchos detalles, pero trato de imaginar un libro de clase formado por páginas. Si quiero imprimir una, dos o más páginas del libro, con su diseño actual puedo hacer:

auto range = ...; for( auto p : book.pages(range) ) { p->print(); }

mientras que por Demeter''s tendrás

auto range = ...; book.print( /* possibly a range here */ );

esto está inclinado hacia una mejor encapsulación, ya que no confía en los detalles internos de la clase de libro y si su estructura interna cambia, no necesita hacer nada con el código de su cliente.

Digamos que tengo una biblioteca que tiene una clase de Document . Una instancia de Document puede poseer varias instancias de Field . Field tiene varias subclases (por ejemplo, IntegerField y StringField ), e incluso el usuario de la API puede StringField subclases y proporcionar instancias de subclases al Document (digamos que el usuario puede desarrollar un tipo personalizado de datos para almacenar en un campo).

Me gustaría exponer las instancias de Field posee el Document través de una API de tal manera que los usuarios puedan interactuar con ellas, pero sin transferir la propiedad .

¿Cuál es la forma correcta de hacer esto?

Yo pense acerca de:

  • Exponiendo una const std::unique_ptr<Field>& reference - esto se siente bastante feo
  • Exponer un puntero de Field* simple: esto no parece correcto porque el usuario puede estar inseguro de si debe eliminar la instancia o no
  • Utilizando std::shared_ptr en std::shared_ptr lugar, esto se siente mal porque la propiedad no se comparte realmente

Por ejemplo,

class Document { private: std::map<std::string, std::unique_ptr<Field> > fields; // ... public: // ... // How is this done properly? const std::unique_ptr<Field> &field(const std::string &name) { return fields[name]; } }

Estoy esperando sus sugerencias.
(También doy la bienvenida a consejos sobre enfoques alternativos como lo que sugirió @Fulvio).


Esto aún no se ha considerado, supongo: devolver un objeto proxy con la misma interfaz.

El titular del objeto proxy tiene la propiedad de ese objeto proxy. El proxy guarda cualquier referencia (débil quizás) al objeto referenciado. Cuando se elimina el objeto, puede provocar un error. El objeto eproxy no tiene propiedad.

Tal vez ya fue mencionado. No estoy tan familiarizado con C ++.


Generalmente no me gusta dar referencias a miembros internos. ¿Qué pasa si otro hilo lo modifica? En cambio, si no puedo entregar una copia, prefiero un enfoque más funcional. Algo como esto.

class Foo { private: std::map<std::string, std::unique_ptr<Bar> > bars; // ... public: // ... template<typename Callable> void withBar(const std::string& name, Callable call) const { //maybe a lock_guard here? auto iter = bars.find(name); if(iter != std::end(bars)) { call(iter->second.get()); } } }

De esta manera, el propietario interno nunca "deja" a la clase que lo posee, y el propietario puede controlar invariantes. También puede tener detalles como hacer que el código sea un noop si la entrada solicitada no existe. Se puede usar como,

myfoo.withBar("test", [] (const Bar* bar){ bar->dostuff(); });


Por lo general, devuelvo referencias a los datos, no la referencia a la unique_ptr :

const Bar &getBar(std::string name) const { return *bars[name]; }

Si desea poder devolver un elemento vacío, puede devolver un puntero en bruto (y nullptr en caso de que esté vacío). O incluso mejor, puede usar boost::optional ( std::optional en C ++ 14).

Si existe la posibilidad de que la referencia sobreviva más tiempo que el propietario (entorno multihilo), uso shared_ptr internamente y devuelvo weak_ptr en los métodos de acceso.


Regresaría Bar& (quizás con una const ).

El usuario deberá comprender que la referencia se invalidará si el elemento se elimina del mapa, pero este será el caso, independientemente del modelo de propiedad única.


Si es posible, trataría de evitar exponer las partes internas del Document pero en su defecto devolvería un const Field& o si necesita que sea nulable un const Field* . Ambos muestran claramente que el Document está reteniendo la propiedad. Además, hacer const el método en sí.

Podría tener una versión no const del método que devuelve un Field& o Field* pero lo evitaría si pudiera.


std::weak_ptr< Bar > un std::weak_ptr< Bar > (si es C ++ 11) o boost::weak_ptr (si no es C ++ 11). Esto hace que sea explícito que esto es memoria de pila y no se arriesga a colgar una referencia a una memoria no existente (como Bar & does). También hace explícita la propiedad.