如何以高效的方式处理非常通用的函数作为参数?

时间:2016-10-11 23:49:57

标签: c++ performance function

假设我们希望尽可能快地栅格化大量的线条,我们希望实际的绘图函数尽可能抽象,即我们需要的所有像素绘图函数,它们唯一共同点是他们的输入是像素坐标:

void plot(int x, int y);

像素绘图函数使用的参数在我们绘制大量线条之前设置,很少或从不更改。

第一个实施理念

我们的线条绘制功能可能看起来像

void raster_line(void (*plot)(int, int), int x0, int y0, int x1, int y1);

只要想要在(x,y)处绘制像素,该函数的实现就会调用pl​​ot(x,y)。大多数时候我们想要栅格到特定缓冲区,所以我们定义一个全局变量并让一个绘图函数作用于该缓冲区:

static int* buffer;
void plot(int x, int y) {
    buffer[x + y * width] = 1;
}

因此,在调用raster_line之前,我们必须设置缓冲区变量,然后传递绘图函数指针。

第二个实施理念

我们的线条绘制功能可能看起来像

void raster_line(const AbstractPlot& ap, int x0, int y0, int x1, int y1);

其中AbstractPlot是接口

class AbstractPlot {
public:
    virtual ~AbstractPlot() {}
    virtual void plot(int x, int y) const = 0;
};

为了具有与第一个示例中相同的功能,我们提供了派生类

class Plot : public AbstractPlot {
public:
    int* buffer;
    void plot(int x, int y) const {
        buffer[x + y * width] = 1;
    }
};

因此,在调用raster_line之前,我们创建一个Plot对象,然后初始化缓冲区成员,然后传递实例。

摘要

我的测试说第一个想法比第二个想法快20%(虚函数表查找速度慢?)但我不喜欢我必须使用全局变量的事实。我对如何绘制线条感兴趣,但是如何使像素绘图尽可能通用(和快速)。有没有更好的方法来解决这个问题?

1 个答案:

答案 0 :(得分:1)

使用 static 多态性可以避免不必要的虚拟调用开销,其中多态行为在编译时使用模板解析。这是大多数C ++标准库例如 std::sort采用的方法。因此

template <class F>
void raster_line(F plot, int x0, int y0, int x1, int y1);

如果plot是没有捕获的lambda函数,因此在实例化raster_line时保证是无法使用的,那么在打开优化时根本就没有开销。如果绘图函数需要具有某种状态,则可以将其包装在functor类或带有捕获的lambda中,而不会对不需要访问任何状态的调用施加任何开销。

这种方法的主要缺点是raster_line的定义必须放在标题中,并由包含标题的每个翻译单元编译。在这种特殊情况下,听起来运行时性能对您来说非常重要,因此接受编译时间的小幅增加可能是值得的权衡。但是你应该小心这样做无处不在,因为编译时间的增加可能是相当大的,而且运行时间的改善很小。