estoy usando shared_ptr y STL ampliamente en un proyecto, y esto lleva a un exceso de largas tipos, propensas a errores como shared_ptr < vector < shared_ptr>> (soy un programador ObjC por preferencia, donde los nombres largos son la norma, y aún así es demasiado.) Sería mucho más claro, creo, llamar constantemente a este FoolistPtr y documentar la convención de nomenclatura que "Ptr" significa shared_ptr y "List" significa vector de shared_ptr.
para principiantes, recomiendo usar buenas estructuras de diseño para el alcance (por ejemplo, espacios de nombres), así como nombres descriptivos, no abreviados para typedefs. FooListPtr
es terriblemente corto, imo. nadie quiere adivinar lo que significa una abreviatura (o se sorprenderá al descubrir que Foo es const, shared, etc.), y nadie quiere alterar su código simplemente por colisiones de alcance.
También puede ayudar elegir un prefijo para typedefs en sus bibliotecas (así como otras categorías comunes).
también es una mala idea para arrastrar tipos fuera de su alcance declarado:
namespace MON {
namespace Diddy {
class Foo;
} /* << Diddy */
/*...*/
typedef Diddy::Foo Diddy_Foo;
} /* << MON */
hay excepciones a esto:
- un tipo privado por completo ecapsualted
- un tipo de contenido dentro de una nuevo alcance
mientras estamos en ello, using
in Se deben evitar los ámbitos del espacio de nombres y los alias del espacio de nombres. Califique el alcance si desea minimizar la futura conservación.
Esto es fácil de escribir, pero está causando dolores de cabeza con los encabezados. Parece que tengo varias opciones para definir FoolistPtr:
Foo.h. Eso entrelaza todos los encabezados y crea serios problemas de compilación, por lo que no es un comienzo.
puede ser una opción para declaraciones que realmente dependen de otras declaraciones. lo que implica que necesita dividir paquetes, o hay una interfaz común y localizada para subsistemas.
FooFwd.h ("encabezado hacia adelante"). Esto es lo que sugiere C++ efectivo, basado en iosfwd.h. Es muy consistente, pero la sobrecarga de mantener el doble de encabezados parece molesto en el mejor de los casos.
no se preocupe por el mantenimiento de esto, realmente. es una buena practica el compilador usa declaraciones avanzadas y typedefs con muy poco esfuerzo. no es molesto porque ayuda a reducir sus dependencias y ayuda a garantizar que todas sean correctas y visibles. realmente no hay más que mantener, ya que los otros archivos hacen referencia al encabezado 'tipos de paquete'.
Común.h (poner todos juntos en un solo archivo). Esto mata la reutilización al entrelazar muchos tipos no relacionados. Ahora no puedes simplemente levantar un objeto y moverlo a otro proyecto. No es un principiante.
las dependencias e inclusiones basadas en paquetes son excelentes (ideal, realmente) - no descarta esto. obviamente tendrá que crear interfaces de paquetes (o bibliotecas) que estén bien diseñadas y estructuradas, y que representen clases de componentes relacionadas. estás haciendo un problema innecesario de la reutilización de objetos/componentes. minimice los datos estáticos de una biblioteca, y permita que las fases de enlace y franja hagan su trabajo. nuevamente, mantenga sus paquetes pequeños y reutilizables y esto no será un problema (suponiendo que sus bibliotecas/paquetes estén bien diseñados).
Algún tipo de fantasía #define magic that typedef's si aún no ha sido typedefed. Tengo una aversión permanente por el preprocesador, porque creo que hace que sea difícil para las personas nuevas que asimilen el código, pero tal vez ....
realidad, es posible declarar un typedef en el mismo ámbito varias veces (por ejemplo, , en dos encabezados separados) - eso no es un error.
declarando un typedef en el mismo ámbito con diferentes tipos subyacentes es un error. obviamente. debes evitar esto, y afortunadamente el compilador hace cumplir eso.
Para evitar esto, cree una 'compilación de traducción' que incluya el mundo: el compilador marcará las declaraciones de los tipos de tipos que no coinciden.
tratando de escabullirse con un mínimo de tipos y/o hacia delante (que son lo suficientemente cerca como para liberar en compilación) no vale la pena el esfuerzo. a veces necesitarás un montón de soporte condicional para las declaraciones hacia adelante; una vez que se define, es fácil (las bibliotecas stl son un buen ejemplo de esto) en el caso de que también declares hacia adelante template<typename,typename>class vector;
).
es mejor tener todas estas declaraciones visibles para detectar cualquier error de inmediato, y puede evitar el preprocesador en este caso como una bonificación.
Use una subclase vectorial en lugar de una typedef. Esto parece peligroso ...
a menudo se señala una subclase de std::vector
como un "error de principiante". este contenedor no estaba destinado a ser subclasificado. no recurra a malas prácticas simplemente para reducir sus tiempos de compilación/dependencias.si la dependencia es que realmente significativa, probablemente debería utilizar PIMPL, de todos modos:
// <package>.types.hpp
namespace MON {
class FooListPtr;
}
// FooListPtr.hpp
namespace MON {
class FooListPtr {
/* ... */
private:
shared_ptr< vector< shared_ptr<const Foo> > > d_data;
};
}
¿Existen mejores prácticas aquí? ¿Cómo aparecen en código real, cuando la reutilización, la legibilidad y la coherencia son primordiales?
En definitiva, he encontrado un pequeño y conciso enfoque basado en paquetes lo mejor para la reutilización, para reducir los tiempos de compilación y reducir al mínimo la dependencia.
¿Puedo preguntar por qué esta pregunta es una wiki de la comunidad? –
@Konrad, si hubiera otras propuestas, sugerí que se agreguen a la lista para que a los lectores posteriores les resulte más fácil ver las distintas opciones separadas de las respuestas en función de sus méritos. ¿Quizás la wiki de la comunidad se usa de manera diferente? –
Y después de más investigaciones redescubrí lo que descubrí la última vez que hice clic en la wiki de la comunidad, que es que no tenía intención de hacer eso ... Espero haber aprendido la lección esta vez. –