没有虚函数的命令模式 (C++)

发布于 2024-07-24 05:56:27 字数 795 浏览 8 评论 0 原文

出于性能原因,我使用 奇怪的重复模板模式以避免虚函数。 我有很多执行数百万次的小命令。 我正在尝试将其纳入命令模式。 我想将大量命令添加到队列中,然后迭代它们逐一执行。 每个命令都使用 CRTP 来避免虚拟功能。 我遇到的问题是命令模式通常是使用指针向量来实现的。 但是当 Command 类被模板化时,传递通用 Command 指针就变得很困难。 我不是 C++ 专家,所以也许有一种明显的方法来存储模板化命令对象的向量? 我一直在尝试使用类似的东西:

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

问题是 Command 不是类型,因此 Command* command 给出编译错误。 我需要使用 Command,但这不起作用,因为我需要队列来保存不同类型的命令。

有什么解决方案的想法吗? 或者虚拟函数是我唯一的选择?

添加:命令对象是蒙特卡罗模拟算法的一部分。 因此,Command 可能是正态分布中的随机数,其中正态分布的参数是该类的一部分。 所以命令模式非常适合。 我有很多按特定顺序调用需要维护状态的函数。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

殊姿 2024-07-31 05:56:27

CRTP 通过在编译时解析对象的运行时类型来发挥其魔力,以便编译器可以内联函数调用。 如果您有一个指向泛型类型的指针向量,则编译器无法确定具体的具体类型,并且无法进行编译时解析。

仅根据您问题中的信息,我认为虚拟功能是您的最佳选择。 然而,虚拟函数并没有那么慢。 当然,它们比内联函数慢,但在许多情况下它们足够快! 特别是当您的进程受 I/O 时间而不是处理时间限制时。

其中之一 >这个问题对此问题进行了一些更深入的讨论。 总而言之,虚拟函数调用的开销可能以纳秒为单位。 它比这更复杂,但重点是你不应该害怕虚拟函数,除非你的函数正在做一些非常琐碎的事情,比如单个赋值。 你说你的命令很小,所以也许是这样的。 我会尝试使用虚拟函数制作一个快速原型,看看是否能提供可接受的性能。

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.

初见 2024-07-31 05:56:27

除非您在编译时构建命令队列,否则您想要的东西是不可能的。

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

你是年少的欢喜 2024-07-31 05:56:27

我无法判断您的命令队列是否经常更改或很少更改。

如果与执行的频率相比它很少改变,在我看来这可能是代码生成的工作。

只需打印出一个程序来执行您需要的操作,编译并运行即可。 动态链接 dll 并加载它。 这应该需要大约一秒钟的时间。 没有类、对象或调度。 如果您单步执行,您将看到几乎所有循环都对您的答案没有实质性贡献。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文