Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Command pattern without virtual functions (C++)

For performance reasons, I am using the the Curiously Reoccuring Template Pattern to avoid virtual functions. I have lots of small commands which execute millions of times. I am trying to fit this into the Command Pattern. I want to add tons of commands to a queue, and then iterate through them executing each one by one. Each Command uses a CRTP to avoid virtual functions. The problem I am running into is that the Command pattern is typically implemented using a vector of pointers. But when the Command class is templated, it becomes hard to pass around generic Command pointers. I'm not a C++ expert, so perhaps there is an obvious way to store a vector of templated command objects? I have been trying to use something like:

boost:ptr_vector commands;
AddCommand(Command* command) {
  commands.push_back(command);
}

The problem is Command is not a type, so Command* command gives a compile error. I need to use Command<CommandType>, but that won't work because I need the queue to hold different types of commands.

Any ideas for solutions? Or are virtual functions my only option?

ADDED: The command objects are part of a monte carlo simulation algorithm. So you might have, Command be a random number from a normal distribution, where the parameters of the normal distribution are part of the class. So the command pattern fits very nicely. I have lots of calls, in a particular order, to functions that need to maintain state.

like image 333
Tristan Avatar asked Jun 11 '09 00:06

Tristan


3 Answers

The CRTP does its magic by resolving the run time type of the object at compile time so that the compiler can inline the function calls. If you have a vector of pointers to a generic type, the compiler cannot determine the specific concrete type, and will not be able to do its compile time resolution.

From just the information you have in your question, I think virtual functions are your best option. However, virtual functions are not that slow. They are slower than an in-lined function, sure, but in many cases they are plenty fast enough! Especially if your process is bounded by I/O time instead of processing time.

One of the answers to this question has some more in depth discussion of this issue. To summarize, the overhead for a virtual function call will likely be measured in nanoseconds. It is more complicated than that, but the point is that you shouldn't be afraid of virtual functions unless your function is doing something really trivial like a single assignment. You said that your commands were small, so perhaps this is the case. I'd try doing a quick prototype with virtual functions and see if that gives acceptable performance.

like image 159
A. Levy Avatar answered Oct 23 '22 17:10

A. Levy


Unless you are building your command queue during compile time, what you want is impossible.

like image 41
rlbond Avatar answered Oct 23 '22 18:10

rlbond


I can't tell if your command queue changes often or seldom.

If it changes seldom, compared to how often it is executed, it seems to me this could be a job for code generation.

Just print out a program to do the actions you need, compile & link a dll on the fly, and load it. That should take about a second. No classes, objects, or dispatching. And if you single-step it, you'll see almost no cycles that don't contribute materially to your answer.

like image 1
Mike Dunlavey Avatar answered Oct 23 '22 17:10

Mike Dunlavey