I'm working in an embedded environment (Arduino/AVR ATMega328) and want to implement the Factory Method pattern in C++. However, the compiler I'm using (avr-gcc) doesn't support the new
keyword. Is there a way of implementing this pattern without using new
?
问题:
回答1:
Since the AVR compiler is based on the gcc compiler, it is very likely to support the new keyword. What exactly is the error you're getting. I'm guessing it's a link/compiler error along the lines of an undefined function, namely, operator new. There is a difference between the new operator and operator new, the first is used to create objects and the latter is used to allocate memory for objects. The new operator calls operator new for the type of object being created, then initialises the object's v-table and calls the object's constructors. Reading this FAQ it says that operator new is not defined in the standard libraries. This is easy to fix, just define one:
void *operator new (size_t size)
{
return some allocated memory big enough to hold size bytes
}
and you'll need to define a delete as well:
void operator delete (void *memory)
{
free the memory
}
The only thing to add is the memory management, the allocation and freeing of blocks of memory. This can be done trivially, being careful not to clobber any existing allocated memory (the code, static / global data, the stack). You should have two symbols defined - one for the start of free memory and one for the end of the free memory. You can dynamically allocate and free any chunk of memory in this region. You will need to manage this memory yourself.
回答2:
If there is no way to instantiate a class at runtime, I suppose this isn't possible. All you could do is to pre-allocate some objects at compile time, create references to them and return them when needed.
回答3:
The big picture of the Factory Method is object creation, which means heap memory consumption. On an embedded system, you are constrained by RAM and need to make all your design decisions with your memory limits in mind. The ATmega328 only has 2 KB RAM. I would recommend against using dynamically allocated memory in such a tight space.
Without knowing your problem in more detail, I would recommend statically declaring a handful of instances of the class and re-use those instances in some fashion. This means you need to know when and why your objects are created and--JUST AS IMPORTANT--when and why they end; then you need to figure out how many you need to have active at one time and how many it is possible to have active at one time.
!!Dean
回答4:
What about something like this?
MyClass *objp = (MyClass*)malloc(sizeof(MyClass));
*objp = MyClass(); // or any other c'tor
EDIT: Forgot to mention, it assumes MyClass has an assignment operator.
EDIT2: Another thing I forgot - yes, there's a gotcha (it's C++, there are always gotchas). You'll have to call the d'tor manually for the object, since you can't use free.
回答5:
If you are using factory means that you want some dynamic binding behavior which indicates that you have some virtual functions. Although, it may be possible to allocate the memory for the object using malloc() the vtable of the class will not be setup properly and hence the call to virtual functions will crash. I don't see any way of doing this when dynamic binding is required.
回答6:
Can you do malloc? If so you can malloc your object that way.
Also what is the nature of your objects that you want to create from the Factory?
- Are they imutable?
- Is the factory only intended to produce a limited set of objects that can be known at compile time?
If the answer is yes to both questions, you can statically allocate the memory for your set of immutable objects and let the factory method return pointers to the appropriate object.
This will not work if the answer is no to either question. Also wuth this approach you have the problem of always having that memory allocated.
回答7:
A way I've solved this problem in an embedded system with strict coding standards (where we were not allowed to use "new" or "delete") was to create a static array of the desired object. And then use static pointers to the already-allocated objects, storing these returned values (using static variables and/or member variables) for later execution of the various objects.
// 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;
}
}
Please be forewarned. This is all from memory as I haven't written any C++ in over 8 months.
Also Note: This has a serious drawback in that you are allocating a bunch of RAM at compile time.