gpt4 book ai didi

c++ - 在虚函数、function_pointer 和 functor 之间进行选择

转载 作者:搜寻专家 更新时间:2023-10-31 00:02:55 24 4
gpt4 key购买 nike

我正在编写一个类,其中一个函数的实现取决于用户。目前我将它作为一个虚函数,用户需要覆盖我的类来提供它的实现。我正在考虑使它成为一个 functor(boost::function)/function_pointer 以便用户可以注册它。应用程序对性能极为关键,速度比看起来漂亮的类更重要。改用仿函数会带来一些性能优势吗?

在大多数情况下,它将是一个自由函数,因此函数指针应该没问题。但我想在某些情况下可能需要状态,因此它需要是一个仿函数。

通过允许注册一个 function_ptr 或一个仿函数并根据一些 bool 调用适当的函数,我是否会获得任何性能优势?与此类似。

class Myclass
{
public:
registerFuncPtr(FuncPtrSignature);
registerFunctor(boost::function func);
private:
someMethod(someArgs)
{
...
if(_isFuncPtr)
_func_ptr(args);
else
_functor(args);
...
}
bool _isFuncPtr;
FuncptrSignature _func_ptr;
boost::function _functor;
}

更新:

我正在编写一个共享库,客户端将动态链接到它。没有 C++0x。 :(

最佳答案

这取决于您的特定用例以及用户添加代码的方式。以下是纯理论分析,但您应该在实际决定之前构建一个现实的场景并测试性能。

如果要在编译时添加代码(即您向用户提供代码,他们创建自己的逻辑并将所有内容编译在一起)那么最好的方法可能是提供一个采用 Functor 类型参数。

template <typename Functor> void doProcessing( Functor f) {
f( data );
}

优点是编译器可以访问整个代码,这意味着它可以就是否内联代码做出最佳决定,并且可能在内联的情况下进一步优化。缺点是您需要使用每个新逻辑重新编译程序,并且您必须将您的产品与用户扩展一起编译,很多时候这是不可能的。

如果要在主要产品编译之后执行扩展,即客户可以生成自己的扩展并将它们用于已编译的可执行文件(想想插件),那么您应该考虑替代方案:

  • 接受函数指针(C 方式)

  • 提供一个仅包含该操作(Java 方式)的接口(interface)(基类)

  • 使用执行类型删除的仿函数包装器 (boost::function/std::function)

这些是按纯性能排序的。 C 方式的成本是三者中较小的,但在大多数情况下与接口(interface)选项的差异可以忽略不计(每个函数调用一个额外的间接寻址)并且它为您购买了在调用对象中保持状态的选项(这将有在第一个选项中通过全局状态完成)。

第三个选项是最通用的,因为它将类型删除应用于用户可调用,并允许用户重用他们现有的通过使用 boost::bindstd::bind 等函数适配器以及 lambdas(如果编译器支持)来编写代码。这是最通用的,给用户留下了最多的选择。但是它有一个相关的成本:在类型删除中有一个虚拟调度加上一个对实际代码段的额外函数调用。

请注意,如果用户必须编写一个函数来使您的界面适应他们的代码,那么手动制作的适配器的成本很可能是等效的,因此如果他们需要通用性,那么 boost::function /std::function 是要走的路。

至于替代方案的成本差异,它们很可能总体上非常小,并且从头开始一个或两个操作是否重要将取决于循环的紧密程度和用户代码的成本是。如果用户代码要执行几百条指令,那么不使用最通用的解决方案可能没有意义。如果循环每秒运行几千次,抓取几条指令也不会有什么不同。返回,编写一个现实的场景并进行测试,并在测试时了解对用户真正重要的内容。在需要几分钟的操作中抓紧几秒钟不值得失去更高级别解决方案的灵 active 。

关于c++ - 在虚函数、function_pointer 和 functor 之间进行选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7213941/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com