Estoy trabajando en un entorno incrustado (Arduino/AVR ATMega328) y quiero implementar el patrón Factory Method en C++. Sin embargo, el compilador que estoy usando (avr-gcc) no admite la palabra clave new
. ¿Hay alguna forma de implementar este patrón sin usar new
?¿Puedo implementar el patrón Factory Method en C++ sin usar new?
Respuesta
Dado que el compilador AVR se basa en el compilador gcc, es muy probable que admita la palabra clave nueva. ¿Cuál es exactamente el error que está recibiendo? Supongo que es un error de enlace/compilación en la línea de una función no definida, es decir, un operador nuevo. Hay una diferencia entre el nuevo operador y el operador nuevo, el primero se usa para crear objetos y el último se usa para asignar memoria a los objetos. El nuevo operador llama al operador nuevo para el tipo de objeto que se está creando, luego inicializa la tabla v del objeto y llama a los constructores del objeto. Reading this FAQ dice que el operador nuevo no está definido en las bibliotecas estándar. Esto es fácil de solucionar, simplemente definir una:
void *operator new (size_t size)
{
return some allocated memory big enough to hold size bytes
}
y tendrá que definir un eliminar así:
void operator delete (void *memory)
{
free the memory
}
La única cosa que añadir es la gestión de la memoria, la asignación y liberación de bloques de memoria. Esto se puede hacer de manera trivial, teniendo cuidado de no dañar ninguna memoria asignada existente (el código, datos estáticos/globales, la pila).Debería tener dos símbolos definidos: uno para el inicio de la memoria libre y otro para el final de la memoria libre. Puede asignar dinámicamente y liberar cualquier porción de memoria en esta región. Tendrá que administrar esta memoria usted mismo.
+1 - Voy a combinar esto con la respuesta de Tal y probarlo. –
¿Se puede hacer malloc? Si es así, puedes malloc tu objeto de esa manera.
¿Cuál es la naturaleza de los objetos que desea crear en la fábrica?
- ¿Son imputables?
- ¿La fábrica solo está destinada a producir un conjunto limitado de objetos que puedan conocerse en tiempo de compilación?
Si la respuesta es sí a ambas preguntas, puede asignar estáticamente la memoria para su conjunto de objetos inmutables y dejar que el método de fábrica devuelva los punteros al objeto apropiado.
Esto no funcionará si la respuesta es no a cualquiera de las preguntas. También con este enfoque, usted tiene el problema de tener siempre esa memoria asignada.
Si no hay forma de instanciar una clase en tiempo de ejecución, supongo que esto no es posible. Todo lo que podría hacer es asignar previamente algunos objetos en el momento de la compilación, crear referencias a ellos y devolverlos cuando sea necesario.
¿Qué tal algo como esto?
MyClass *objp = (MyClass*)malloc(sizeof(MyClass));
*objp = MyClass(); // or any other c'tor
EDIT: He olvidado mencionar, que asume MyClass tiene un operador de asignación.
EDIT2: Otra cosa que olvidé - sí, hay una gotcha (es C++, siempre hay errores). Tendrás que llamar manualmente al objeto para el objeto, ya que no puedes usarlo gratis.
Al menos funciona en VC++ 7. – sharptooth
Mi madre siempre me advirtió sobre el uso de malloc() para crear una instancia de un objeto C++. Aunque está llamando al constructor y copiando sus datos a la memoria asignada, ¿hay algún problema con este enfoque? –
Sí, hay errores obvios: el bloque de memoria no está inicializado, por lo que el operador de asignación debería reaccionar en consecuencia; si ve un miembro de puntero "inicializado", no debería intentar liberarlo porque contiene basura y está colgando. Supongo que lo mejor es simplemente llamar a calloc() para obtener un bloque de memoria inicializado cero para evitar eso. – sharptooth
Si está utilizando la fábrica significa que desea un comportamiento de enlace dinámico que indique que tiene algunas funciones virtuales. Aunque, puede ser posible asignar la memoria para el objeto usando malloc() el vtable de la clase no se configurará correctamente y, por lo tanto, la llamada a las funciones virtuales se bloqueará. No veo ninguna forma de hacerlo cuando se requiere enlace dinámico.
Eso podría solucionarse: asigne un objeto en la pila y llame a memcpy para que el puntero vtable lo copie en el objeto recientemente asignado. – sharptooth
¿Estás diciendo que la respuesta de Tal (http://stackoverflow.com/questions/1031301/can-i-implement-the-factory-method-pattern-inc-c-without-using-new/1031375#1031375) ganó no funciona? –
No lo he probado. Pero según mi no funcionará. Sin embargo, la solución sugerida por sharptooth puede funcionar. – Naveen
Una manera que he resuelto este problema en un sistema integrado con estrictas normas de codificación (donde no se nos permitía usar "nuevo" o "eliminar") era crear una matriz estática del objeto deseado. Y luego use punteros estáticos para los objetos ya asignados, almacenando estos valores devueltos (usando variables estáticas y/o variables de miembros) para la posterior ejecución de los diversos objetos.
// Class File ---------------------------------------------------
class MyObject {
public:
MyObject* getObject();
private:
const int MAX_POSSIBLE_COUNT_OF_OBJECTS = 10;
static MyObject allocatedObjects[MAX_POSSIBLE_COUNT_OF_OBJECTS];
static allocatedObjectIndex = 0;
};
// Implementation File ------------------------------------------
// Instantiate a static array of your objects.
static MyObject::allocatedObject[MAX_POSSIBLE_COUNT_OF_OBJECTS];
// Your method to return already created objects.
MyObject* MyObject::getObject() {
if (allocatedObjectIndex < (MAX_POSSIBLE_COUNT_OF_OBJECTS - 1)) {
return allocatedObjects[allocatedObjectIndex++];
} else {
// Log error if possible
return NULL;
}
}
Tenga en cuenta. Todo esto es de memoria ya que no he escrito ningún C++ en más de 8 meses.
También Nota: Esto tiene un serio inconveniente ya que está asignando un montón de RAM en tiempo de compilación.
Puede definir un operador MyObject :: operator new (size_t) que haga todo lo anterior, es decir, use una matriz preasignada, mientras mantiene la nueva sintaxis de MyObject (args) familiar en lugar de algo no estándar. De esta forma, puedes construir y destruir objetos correctamente. – Skizz
En un sistema integrado, considero que asignar un montón de RAN en tiempo de compilación es una buena cosa, no un inconveniente –
La idea general del método de fábrica es la creación de objetos, lo que significa un consumo de memoria en montón. En un sistema integrado, la RAM lo limita y necesita tomar todas las decisiones de diseño teniendo en cuenta los límites de memoria. El ATmega328 solo tiene 2 KB de RAM. Recomendaría no utilizar memoria asignada dinámicamente en un espacio tan reducido.
Sin conocer su problema con más detalle, recomendaría estáticamente declarar un puñado de instancias de la clase y volver a utilizar esas instancias de alguna manera. Esto significa que necesita saber cuándo y por qué se crean sus objetos y, ASÍ COMO IMPORTANTE, cuándo y por qué terminan; entonces necesita averiguar cuántos necesita tener activados al mismo tiempo y cuántos es posible tener activo a la vez.
Dean
Todo porque tiene 2 KB o RAM no significa que no se pueda asignar la memoria dinámica. Usted simplemente no puede asignar tanto. Puede obtener 500 objetos de dos bytes allí (500 * (2 para el objeto + 2 para información de asignación) = 2000). – Skizz
Skizz, tus dos primeras oraciones son correctas, pero la tercera no es razonable. Los 2 KB RAM (2048 bytes) contienen tanto la pila C como la pila; por lo que solo tendría 48 bytes para su stack C (no razonable). Un programa que necesita un Método de fábrica no es simple, por lo que su pila de llamadas C va a variar en profundidad y podría sobrescribir objetos en el montón. La asignación de memoria dinámica es posible, pero no segura en un grupo de memoria tan pequeño. La asignación de memoria estática será más fácil de administrar y tendrá más probabilidades de generar un programa que funcione correctamente. – dwhall
- 1. Factory Method
- 2. Tipo Casting y el patrón Factory
- 3. Spring 3 @Component y static factory method
- 4. ¿Cuáles son las diferencias entre los patrones Builder, Factory Method y Abstract Factory?
- 5. ¿Cuáles son los usos prácticos de Factory Method Pattern?
- 6. C# Factory Pattern
- 7. Cómo implementar el patrón aplicar en Javascript
- 8. ¿Cómo implementar el patrón de prototipo?
- 9. ¿Puedo usar el Patrón de Plantilla Curiosamente Recurrente aquí (C++)?
- 10. Cómo implementar el patrón MVC sin mantener Vistas activas
- 11. Cómo implementar el patrón MVC en Tkinter
- 12. ¿Cómo puedo usar Factory Girl en db/seeds?
- 13. ¿Cómo implementar el patrón flyweight en php?
- 14. Factory/Abstract Factory confusion
- 15. Secuencias Factory Girl sin incrementar
- 16. C# method group strangeness
- 17. C++ Abstract Factory usando plantillas
- 18. Problemas al implementar el patrón "Observer"
- 19. ¿Cómo puedo usar el patrón de tortas de Scala para implementar las patas del robot?
- 20. override C++ virtual method
- 21. Implementar el servicio web java sin usar el servidor web
- 22. Implementar el patrón Async clásico con TPL
- 23. ¿Es posible implementar X-HTTP-Method-Override en ASP.NET MVC?
- 24. ¿Cómo puedo implementar un generador en C++?
- 25. ¿Cómo usar el patrón de estrategia con C#?
- 26. ¿Cómo puedo implementar 'tee' programáticamente en C?
- 27. ¿Cómo implementar el patrón de visitante en javascript?
- 28. patrón de la fábrica adecuada en C++
- 29. C# List.Find method - ¿cómo puedo pasar un valor en el predicado?
- 30. Cómo usar Spring's ThreadPoolExecutorFactoryBean factory bean
¿Cómo se asigna la memoria? D: – GManNickG
Aparte de eso, ¿admite la colocación nueva? Lo mejor que puedo pensar es asignar estáticamente un trozo de memoria, luego puedes colocar algo nuevo allí. – GManNickG
La memoria está asignada en la pila (incluida la construcción de objetos basada en pila) o con malloc(), que no es compatible con la construcción de objetos. La colocación nueva no es compatible tampoco ... –