I have this optimization problem where my program goes through a configuration phase then an execution phase. During configuration, an implementation of a function is selected, then this function is called at each loop iteration during execution.
I want to avoid going through switch/case at each loop to check which function to call. Solution is a function pointer. Now each of these function can have an internal state. A good solution would be inheritance where each class implements the "do_something()" function of the base class and the compiler makes a vtable and everything is fine.
Now, I also want to optimize memory usage. Since I always use one implementation at the time, the internal state of each instance can share the same memory space. This becomes a problem as I can't put inherited instances into a union; compiler is not happy about it (it make sense I guess, because of the vtable probably).
The best solution I found to that problem is to declare a structure of data that uses a union outside of the classes and pass a pointer to it to each instance of the class.
Is there a better way to do?
EDIT : In this case, no dynamic allocation is to be used.
See code below:
The problem
#include <stdio.h>
using namespace std;
class Base{
public:
virtual void doprint() = 0;
};
class ChildA : public Base{
public:
virtual void doprint(){
printf("I am A : %d",foo);
};
int foo;
};
class ChildB : public Base{
public:
virtual void doprint(){
printf("I am B : %u", bar);
};
unsigned int bar;
};
int main()
{
// Changing this for a struct works
union{
ChildA a;
ChildB b;
} u;
// Configure phase
u.a.foo = -10;
Base *pbase = &u.a;
// Exec phase
pbase->doprint();
return 0;
}
The above code make the compiler say:
error: union member ‘main()::::a’ with non-trivial ‘ChildA::ChildA()’
The ugly solution
#include <stdio.h>
using namespace std;
union InternalData{
struct {
int foo;
} data_for_a;
struct {
unsigned int bar;
} data_for_b;
};
class Base{
public:
void init(InternalData *data)
{
m_data = data;
}
virtual void doprint() = 0;
protected:
InternalData* m_data;
};
class ChildA : public Base{
public:
virtual void doprint(){
printf("I am A : %d", m_data->data_for_a.foo);
};
};
class ChildB : public Base{
public:
virtual void doprint(){
printf("I am B : %u", m_data->data_for_b.bar);
};
};
int main()
{
ChildA a;
ChildB b;
InternalData internal_data;
// Configure phase
internal_data.data_for_a.foo = -10;
a.init(&internal_data);
Base *pbase = &a;
// Exec phase
pbase->doprint();
return 0;
}
CodePudding user response:
You don't really want a union
(nobody ever really wants a union...)
What you really want is a place to place your implementations into, and to get an interface pointer out, and a guarantee that it's properly destroyed afterwards.
std::variant< ChildA, ChildB> impl; //define buffer that correctly destroys
Base *pbase; //declare the Base pointer.
impl = ChildA{}; //assign it an implementation
pbase = std::get<ChildA>(impl); //assign pointer to that implementation
If you C doesn't have std::variant
, then you can implement the key pieces for a destructing buffer yourself. A minimal version looks something like this:
template<class Base, std::size_t size, std::size_t align>
class buffer {
static_assert(std::has_virtual_destructor_v<Base>);
std::aligned_storage_t<size, align> rawbuffer;
Base* pbase=0;
public:
~buffer() {if (pbase) pbase->~Base();};
Base* get() {return pbase;}
template<class T, class...Us>
Base* construct(Us&&...vs) {
static_assert(sizeof(T) <= sizeof(rawbuffer));
assert(pbase == nullptr);
pbase = new(reinterpret_cast<T*>(&rawbuffer)) T(std::forward<Us>(vs)...);
return pbase;
}
};
Note that you'll almost certainly want your Base
to have a virtual
destructor.
https://coliru.stacked-crooked.com/a/4d08c8b3b9625988