I'm working on an embedded system, where memory is scarce, and more importantly, since there's a soft realtime constraint (i.e. it's a bug if we don't make the deadline, but no one dies), I cannot use dynamic memory allocation.
However, there's the occasional need to re-initialize a subsystem, and there's been a number of bugs related to not-quite-everything getting either cleaned up or reset correctly. This is of course exactly the problem that constructors and destructors are supposed to solve, but since we don't allocate dynamically, we can't use the idiom where we'd destruct the object and then allocate a new one from scratch (mostly the objects of relevance here are globals).
So in the end there's usually setup code in a constructor, and a reinitialize -type function, which resemble each other but are not identical, since the reinitialize function also does a lot of what a destructor would do.
One way out that I'm thinking of is to write a "renew" -template (this is just a draft, may contain erors and possibly not complet):
template<typename T, typename .. Args>
void renew(T & obj, Args&&... args) {
obj.~T();
new(&obj) T(std::forward<Args>(args)...);
}
which could be used to reinitialize non-dynamically alloctated variables. So for example
A a{17};
... //Do something with a
renew(a, 14);
...//work with the new a, no need to reallocate memory
This would allow getting some of the advantages of constructors and destructors (primarily single way to initialize and deinitialize an object) without dynamic memory allocation. Note that the usage above is simplified, in practice this would mostly be used in very specific points in the main loop and on global objects representing the actual physical subsystems.
Question: is this a sensible way of going about it? Or is there a better alternative?
There's a very similar question here Calling a constructor to re-initialize object. I'm asking much the same thing but specifically in context of embedded programming, where I can't do things the usual way with dynamic allocation.
There are two ways to initialize a class object: Using a parenthesized expression list. The compiler calls the constructor of the class using this list as the constructor's argument list. Using a single initialization value and the = operator.
A constructor is a special member function that is automatically called by the compiler when an object is created and the destructor is also a special member function that is also implicitly called by the compiler when the object goes out of scope.
Dynamic initialization of object refers to initializing the objects at run time i.e. the initial value of an object is to be provided during run time. Dynamic initialization can be achieved using constructors and passing parameters values to the constructors.
Dynamic memory allocation and constructors and destructors are completely unrelated.
If you are using new or delete (like in your renew function), you are using dynamic memory allocation.
A constructor or destructor does not always mean you are dynamically allocating memory.
The 'renew' function should probably be implemented in the operator= of the class, not as an external function, so:
A a{17}
...
a = 14;
...
Example of what you should do:
class TwoInts
{
private:
int int1;
int int2;
public:
TwoInts(int a = 6, int b = 7): int1(a), int2(b) {}
TwoInts(const TwoInts& other): int1(other.int1), int2(other.int2) {}
TwoInts& operator=(TwoInts& other)
{
a = other.a;
b = other.b;
}
};
TwoInts i(16);
//do stuff
i = TwoInts(68, 14);
//do stuff
The above code does not do any memory allocation.
The only reason I see were you would like to your the construction you propose is where the new class would be of a different derived type. But in this case you would have to be really be careful to use the exact same amount of memory, not to override following variables. I know of one example where this is used in mbed. It used to retype their function callbacks, search for "new" and you will various examples.
I am wondering if you have considered using a "clear" function in your class? In my honest opinion as far as I can see now this would be the easiest solution.
An alternative solution would be to write a memory manager which has a fixed buffer size. From this buffer you can then "dynamically" allocate memory. I do not think this is the solution you are looking for as this is more useful for when you often need to allocate and deallocate multiple objects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With