I am wondering about this. Is there a good way to do event messages between two large-scale loose-coupled parts of a game program without having to dynamically allocate and deallocate the messages? Messages may need to be queued, and there can be different types of messages, which suggests an inheritance hierarchy and that's where the dynamic memory stuff comes from, at least when using C++ as I'd be in this case. Thanks.
Big bloated generic "event" systems are overkill. Write something specific.
e.g. Producer and Consumer are decoupled, but an application wants one to forward an event to the other:
class Producer
{
public:
Producer( const std::function<void(int)>& onFrobnicate )
: onFrobnicate(onFrobnicate)
, foo() {}
void Frobnicate()
{
onFrobnicate(foo++);
}
private:
std::function<void(int)> onFrobnicate;
int foo;
};
class Consumer
{
public:
Consumer() : foo() {}
void Foo( int x )
{
foo += x;
}
private:
int foo;
};
class Application1
{
public:
Application1()
: producer(std::bind( &Consumer::Foo, consumer, _1 ))
{
for( int i=0; i!=10; ++i )
producer.Frobnicate(); // calls consumer.Foo 10 times
}
private:
Consumer consumer;
Producer producer;
}
Or if the application wants to buffer the events:
class Application2
{
public:
Application2()
: producer([&](int x){events.push_back(x);})
{
//we expect to buffer 10 events, so let's pre-allocate that much memory as an optimization:
events.reserve(10);
for( int i=0; i!=10; ++i )
producer.Frobnicate(); // pushes 10 results into 'events'
//now send the buffered events to the consumer:
for(auto i: events)
consumer.Foo(i);
events.clear();
}
private:
Consumer consumer;
Producer producer;
std::vector<int> events;
}
Isn't that easier than using some big inheritance-based messaging framework? C++ has tools for this already
To answer the other question -- if you did need to dynamically create a big stack of temporary messages, I'd use a pool allocator, or even better, a stack allocator. Stack allocators are the cheapest possible allocation of any algorithm, and are built around bulk destruction (freeing every allocation made at the same time).
In the above code, the vector acts like a stack allocator, which is a good start, and could be optimized further by replacing it with a hand-coded/optimized stack allocator.