Могу ли я реализовать шаблон Factory Method в C ++, не используя new? - PullRequest
6 голосов
/ 23 июня 2009

Я работаю во встроенной среде (Arduino / AVR ATMega328) и хочу реализовать шаблон Factory Method в C ++. Однако используемый мной компилятор (avr-gcc) не поддерживает ключевое слово new. Есть ли способ реализовать этот шаблон без использования new?

Ответы [ 7 ]

8 голосов
/ 23 июня 2009

Поскольку компилятор AVR основан на компиляторе gcc, весьма вероятно, что он поддержит новое ключевое слово. Какую именно ошибку вы получаете. Я предполагаю, что это ошибка ссылки / компилятора вдоль строк неопределенной функции, а именно, оператора new. Существует разница между оператором new и оператором new: первый используется для создания объектов, а второй - для выделения памяти для объектов. Оператор new вызывает оператор new для типа создаваемого объекта, затем инициализирует v-таблицу объекта и вызывает конструкторы объекта. Чтение этого FAQ говорит, что оператор new не определен в стандартных библиотеках. Это легко исправить, просто определите одно:

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

и вам также нужно определить удаление:

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

Единственное, что нужно добавить - это управление памятью, выделение и освобождение блоков памяти. Это можно сделать тривиально, следя за тем, чтобы не затереть существующую выделенную память (код, статические / глобальные данные, стек) У вас должно быть определено два символа - один для начала свободной памяти и один для конца свободной памяти. Вы можете динамически распределять и освобождать любой фрагмент памяти в этом регионе. Вам нужно будет самостоятельно управлять этой памятью.

3 голосов
/ 24 июня 2009

Общая картина фабричного метода - создание объекта, что означает потребление кучи памяти. Во встроенной системе вы ограничены оперативной памятью и должны принимать все свои проектные решения с учетом ограничений памяти. ATmega328 имеет только 2 КБ оперативной памяти. Я бы рекомендовал не использовать динамически выделяемую память в таком ограниченном пространстве.

Не зная вашей проблемы более подробно, я бы рекомендовал статически объявить несколько экземпляров класса и повторно использовать эти экземпляры каким-либо образом. Это означает, что вам нужно знать, когда и почему создаются ваши объекты и - ПРОСТО ВАЖНО - когда и почему они заканчиваются; тогда вам нужно выяснить, сколько вам нужно, чтобы активировать за один раз и сколько можно активировать за один раз.

!! Dean

3 голосов
/ 23 июня 2009

Если нет способа создать экземпляр класса во время выполнения, я полагаю, это невозможно. Все, что вы можете сделать, - это предварительно выделить некоторые объекты во время компиляции, создать ссылки на них и вернуть их при необходимости.

1 голос
/ 23 июня 2009

Как насчет этого?

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

РЕДАКТИРОВАТЬ: забыл упомянуть, предполагается, что MyClass имеет оператор присваивания.

EDIT2: Еще одна вещь, которую я забыл - да, есть гоча (это C ++, всегда есть гуча). Вам придется вызывать d'tor вручную для объекта, так как вы не можете использовать free.

0 голосов
/ 24 июня 2009

Я решил эту проблему во встроенной системе со строгими стандартами кодирования (где нам не разрешалось использовать «новый» или «удалить») - создать статический массив нужного объекта. А затем используйте статические указатели на уже выделенные объекты, сохраняя эти возвращаемые значения (используя статические переменные и / или переменные-члены) для последующего выполнения различных объектов.

// 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;
    }
}

Пожалуйста, будьте предупреждены. Это все из памяти, так как я не писал C ++ более 8 месяцев.

Также обратите внимание: у этого есть серьезный недостаток в том, что вы выделяете кучу оперативной памяти во время компиляции.

0 голосов
/ 23 июня 2009

Если вы используете фабрику, это означает, что вам нужно динамическое связывание, которое указывает, что у вас есть некоторые виртуальные функции. Хотя может быть возможно выделить память для объекта с помощью malloc (), виртуальная таблица класса не будет настроена должным образом, и, следовательно, вызов виртуальных функций завершится сбоем. Я не вижу способа сделать это, когда требуется динамическое связывание.

0 голосов
/ 23 июня 2009

Можете ли вы сделать malloc? Если это так, вы можете подобрать свой объект таким образом.

Кроме того, какова природа ваших объектов, которые вы хотите создать на Фабрике?

  • Они неизменны?
  • Предполагается ли, что фабрика будет производить только ограниченный набор объектов, которые могут быть известны во время компиляции?

Если ответ на оба вопроса положительный, вы можете статически выделить память для набора неизменяемых объектов и позволить фабричному методу возвращать указатели на соответствующий объект.

Это не будет работать, если ответ на любой вопрос будет отрицательным. Также при таком подходе у вас всегда есть проблема с выделением этой памяти.

...