C ++ lambdas作为类方法

时间:2018-03-07 19:08:51

标签: c++ performance class methods lambda

作为一个假设的问题,我想使用lambdas作为类方法。我知道这在专业背景下很糟糕,但无论如何我很好奇。一个例子可能最适合展示我想做的事情。这是复数的基本类:

class Complex {
    private:
        double re, im;
    public:
        Complex() : re(0.0), im(0.0) {}
        Complex(double re, double im) : re(re * 1.0), im(im * 1.0) {}
        Complex(const Complex &c) = default;

        ~Complex() = default;

        function<double(void)> getRe = [=]() -> double { return re; };
        function<void(double)> setRe = [&](double re) -> void { this->re = re; };

        function<double(void)> getIm = [=]() -> double { return im; };
        function<void(double)> setIm = [&](double im) -> void { this->im = im; };

};

首先,我尝试使用auto而不是明确指定函数类型,但我收到错误,说我无法在非静态字段中使用auto

这似乎确实有效,因为它显然产生了所需的行为。我用它来使用OpenGL绘制一些分形,所以最终做了一些相当密集的工作。

正如我所说,它似乎有用,我特别使用了引用捕获器,因为我认为因为this是对当前实例的引用,所以可能需要它,并且为了获取者的值捕获默认情况下,标识符最终在类范围内搜索(在本例中)并查找字段。

我有两个问题:

  1. 我没有用visual studio测试过这个,但是我正在使用的是CLion和MSVC编译器,this被突出显示为一个不存在的变量(即使它“有效”)。有什么想法会发生这种情况吗?

  2. 课程结束时很慢。因为在一个数量级以上慢。当我使用普通的getter和像double getRe() {return re;}这样的setter时,渲染从绝对瞬间变为2-3秒。为什么会这样?

2 个答案:

答案 0 :(得分:4)

我喜欢这个主意,但在实践中效果并不好。

std::function是一个类类型,就像您可能编写的任何其他自定义类一样。 sizeof(std::function)因实现而异,但合理的值为24字节 1 。这意味着,对于要添加的每个成员24,您要为sizeof(Complex)添加std::function个字节,而为每个成员函数添加0个字节。与大多数计算机上的sizeof(double) == 8相比,这是一个很大的开销:您的Complex类型可能是16个字节,而是大约112个字节。

此外,每个std::function成员都必须初始化,可能需要堆分配,并且由于类型擦除,调用std::function涉及虚函数(或等效函数)。这使得编译器很难优化并且几乎不可能使编译器内联函数,而常规成员函数几乎可以保证内联,因为它们很简单。

std::function用于成员函数意味着您的类型无用大,初始化需要更多工作,并且更难以优化。这就是为什么它要慢得多。

1:目前,sizeof(std::function)实际上32字节,48字节和libstdc++, libc++, and MSVC's STL respectively 上的64字节

为了避免每个对象的开销,你可以有static constexpr个成员(至少在C ++ 17中),但是你必须有一个明确的this参数,它会删除所有成员函数有的好糖。您必须写Complex::getRe(myComplex)而不是myComplex.getRe()

答案 1 :(得分:0)

让我为您修复此代码:

struct Complex {
    double re, im;
    Complex() : re(0.0), im(0.0) {}
    Complex(double re, double im) : re(re * 1.0), im(im * 1.0) {}
    Complex(const Complex &c) = default;

    ~Complex() = default;
};

完全相同的结果,更好的可读性,更小的内存占用。去吧。对于const-correctness,你的代码也非常糟糕。

是的,由于多种因素,您的代码非常慢:

  • 你对方法的调用现在已经虚拟化了,因此它们没有内联,你最终因此受到了极大的惩罚
  • 您的对象创建/销毁现在很可能会产生动态内存分配/解除分配
  • 您的对象没有变大,因此更多缓存未命中