以未知的顺序执行函数的最有效方法
Most effective method of executing functions an in unknown order
假设我有一个很大的,在50到200之间的单个函数池,它们的工作是对单个对象进行操作并修改它。函数池被选择性地放入单个数组中,并按任意顺序排列。
函数本身不接受它正在修改的对象内存在的值以外的参数,这样,对象的行为仅由哪些函数以何种顺序执行决定。
到目前为止,我暂时使用的一种方法是这样的,它可以更好地解释我的目标是什么:class Behavior{
public:
virtual void act(Object * obj) = 0;
};
class SpecificBehavior : public Behavior{
// many classes like this exist
public:
void act(Object * obj){ /* do something specific with obj*/ };
};
class Object{
public:
std::list<Behavior*> behavior;
void behave(){
std::list<Behavior*>::iterator iter = behavior.front();
while(iter != behavior.end()){
iter->act(this);
++iter;
};
};
};
我的问题是,从性能和可维护性方面考虑,c++中组织这样一个函数池的最有效的方法是什么?这是我正在做的一些人工智能研究,这种方法与我试图实现的目标最接近。
edits:数组本身可以在任何时候被此处未列出的代码的任何其他部分更改,但它保证在调用behave()
期间永远不会更改。存储它的数组需要能够更改和扩展到任意大小
如果行为函数没有状态,只接受一个Object
参数,那么我会使用函数对象的容器:
#include <functional>
#include <vector>
typedef std::function<void(Object &)> BehaveFun;
typedef std::vector<BehaveFun> BehaviourCollection;
class Object {
BehaviourCollection b;
void behave() {
for (auto it = b.cbegin(); it != b.cend(); ++it) *it(*this);
}
};
现在只需将所有函数加载到集合中。
如果你将对这个集合做的主要事情是对它进行迭代,你可能会想要使用vector
作为解引用和递增你的迭代器将等同于简单的指针算术。
如果你想使用所有的内核,而你的操作不共享任何状态,你可能想看看像Intel的TBB这样的库(参见parallel_for example)
我会保持原样。性能应该是OK的(可能会有额外的间接由于虚表查找,但这应该无关紧要)
我保持原样的原因是:
-
你可以将公共子行为提升到behavior和你的实现类之间的中间类。使用函数指针就不那么容易了。
struct AlsoWaveArmsBase : public Behaviour { void act( Object * obj ) { start_waving_arms(obj); // Concrete call do_other_action(obj); // Abstract call end_waving_arms(obj); // Concrete call } void start_waving_arms(Object*obj); void end_waving_arms(Object*obj); virtual void do_other_actions(Object * obj)=0; }; struct WaveAndWalk : public AlsoWaveArmsBase { void do_other_actions(Object * obj) { walk(obj); } }; struct WaveAndDance : pubic AlsoWaveArmsBase { void do_other_actions(Object * obj) { walk(obj); } }
-
你可能想在你的行为中使用状态
struct Count : public Behavior { Behaviour() : i(0) {} int i; void act(Object * obj) { count(obj,i); ++i; } }
-
您可能想要添加辅助功能,例如,您可能想要添加
can_act
这样:void Object::behave(){ std::list<Behavior*>::iterator iter = behavior.front(); while(iter != behavior.end()){ if( iter->can_act(this) ){ iter->act(this); } ++iter; }; };
在我看来,这些灵活性超过了转向纯函数方法的好处。
对于可维护性,您当前的方法是最好的(虚函数)。您可能从使用自由函数指针中获得一点好处,但我怀疑它是可测量的,即使是这样,我也不认为值得这么麻烦。当前的OO方法足够快且可维护。我正在谈论的小收益来自于这样一个事实,即您对指向对象的指针解引用,然后(在幕后)对指向函数的指针解引用(这发生在调用虚函数的实现中)。
我不会使用std::function,因为它不是很高性能(尽管在不同的实现中可能会有所不同)。看这个和这个。当你在运行时需要这种动态时,函数指针是最快的。
如果你需要提高性能,我建议你去改进算法,而不是这个实现。
- 为什么将值返回函数传递给重载=运算符对运算符函数有效,而对其他运算符无效
- 递归函数有效,但无法记忆
- 将此布尔值传递给此函数的最有效方法是什么?
- 在函数内创建的对象的范围 - 如果在函数外部存储和访问引用,它们是否有效?
- 我如何知道作为参数的size_t在函数中是否有效?
- C++ 返回指向函数内定义的静态数组的指针是否有效?
- 为什么TinyXML2的XMLDocument::FirstChild()函数在尝试解析这个有效的XML文件时返回NULL?
- 文本 RPG - 使用函数检查有效的输入
- 将 C 函数转换为 C++ 以检查数字是否有效
- 函数参数的名称与调用函数时使用的变量相同是否有效?
- 为什么使用不匹配的参数调用重载函数仍然有效
- 在函数中按值传递 unordered_map/unordered_set 是否有效? C++
- 我们如何并行运行算法的 n 个实例并以有效的方式计算结果函数的平均值?
- 仅当一个参数中未使用 std::function 时,模板函数替换才有效
- 通过指针调用模板类成员函数 [为什么这是有效的 c++]?
- 在 c++ 中将对象设置为等于同一类的构造函数是否有效?
- 传递非泛型函数的最有效方法是什么?
- 为什么我在函数中使用引用并通过引用返回它仍然有效?
- 我应该将哪种有效负载类型发送给webrtc::P ayloadRouter的构造函数?
- 应用一组 N 个函数的第一个有效函数