Pregunta

Estoy trabajando en un entorno incrustado (Arduino / AVR ATMega328) y quiero implementar el patrón Método de fábrica en C ++. Sin embargo, el compilador que estoy usando (avr-gcc) no admite la palabra clave new . ¿Hay alguna manera de implementar este patrón sin usar new ?

¿Fue útil?

Solución

Dado que el compilador AVR se basa en el compilador gcc, es muy probable que admita la nueva palabra clave. ¿Cuál es exactamente el error que está recibiendo? Supongo que es un error de enlace / compilador en la línea de una función indefinida, a saber, operador nuevo. Hay una diferencia entre el operador nuevo y el operador nuevo, el primero se usa para crear objetos y el segundo 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. Leyendo estas preguntas frecuentes dice que el operador nuevo no está definido en Las bibliotecas estándar. Esto es fácil de solucionar, solo defina uno:

void *operator new (size_t size)
{
  return some allocated memory big enough to hold size bytes
}

y también necesitará definir una eliminación:

void operator delete (void *memory)
{
   free the memory
}

Lo único que se puede agregar es la administración de memoria, la asignación y la liberación de bloques de memoria. Esto se puede hacer trivialmente, teniendo cuidado de no bloquear ninguna memoria asignada existente (el código, los datos estáticos / globales, la pila). Debe tener dos símbolos definidos: uno para el inicio de la memoria libre y otro para el final de la memoria libre. Puede asignar y liberar dinámicamente cualquier fragmento de memoria en esta región. Deberá administrar esta memoria usted mismo.

Otros consejos

Si no hay forma de crear una instancia de una clase en tiempo de ejecución, supongo que esto no es posible. Todo lo que puede hacer es preasignar algunos objetos en tiempo de compilación, crear referencias a ellos y devolverlos cuando sea necesario.

El panorama general del Método Factory es la creación de objetos, lo que significa el consumo de memoria del montón. En un sistema embebido, la memoria RAM lo limita y necesita tomar todas sus decisiones de diseño teniendo en cuenta sus límites de memoria. El ATmega328 solo tiene 2 KB de RAM. Recomendaría no usar memoria asignada dinámicamente en un espacio tan reducido.

Sin conocer su problema con más detalle, recomendaría declarar estáticamente un puñado de instancias de la clase y reutilizar esas instancias de alguna manera. Esto significa que necesita saber cuándo y por qué se crean sus objetos y, SOLO IMPORTANTE, cuándo y por qué terminan; entonces necesita averiguar cuántos necesita tener activo a la vez y cuántos es posible tener activo a la vez.

!! Dean

¿Qué pasa con algo como esto?

MyClass *objp = (MyClass*)malloc(sizeof(MyClass));
*objp = MyClass();  // or any other c'tor

EDITAR: se olvidó de mencionar que asume que MyClass tiene un operador de asignación.

EDIT2: Otra cosa que olvidé: sí, hay un problema (es C ++, siempre hay problemas). Tendrá que llamar al d'tor manualmente para el objeto, ya que no puede usar gratis.

Si está utilizando la fábrica significa que desea un comportamiento de enlace dinámico que indica que tiene algunas funciones virtuales. Aunque, es posible asignar la memoria para el objeto usando malloc (), la 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.

¿Puedes hacer malloc? Si es así, puede colocar su objeto de esa manera.

¿Cuál es la naturaleza de sus objetos que desea crear desde la Fábrica?

  • ¿Son imputables?
  • ¿La fábrica solo tiene la intención de producir un conjunto limitado de objetos que se puedan conocer 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 punteros al objeto apropiado.

Esto no funcionará si la respuesta es no a cualquiera de las preguntas. También con este enfoque tiene el problema de tener siempre esa memoria asignada.

Una forma de resolver este problema en un sistema incrustado con estrictos estándares 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 miembro) para la ejecución posterior 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 cuidado. Todo esto es de memoria ya que no he escrito ningún C ++ en más de 8 meses.

También tenga en cuenta: Esto tiene un serio inconveniente en que está asignando un montón de RAM en tiempo de compilación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top