代码之家  ›  专栏  ›  技术社区  ›  Rares Dima

C++lambdas作为类方法

  •  7
  • Rares Dima  · 技术社区  · 8 年前

    作为一个假设问题,我想使用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 我没有显式地指定函数类型,但我得到了一个错误,说我不能使用 汽车 在非静态字段中。

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

    正如我所说,这似乎是可行的,我已经为二传手使用了引用捕获,尤其是自从我发现 this 是对可能需要的当前实例的引用,以及getter的值捕获,因为默认情况下,标识符最终会在类范围中搜索(在本例中)并找到字段。

    我有两个问题:

    1. 我没有用visual studio对此进行测试,但在我使用的CLion和MSVC编译器中 突出显示为不存在的变量(即使它“有效”)。你知道为什么会这样吗?

    2. 这门课最终变得很慢。就像在一个数量级以上的地方一样慢。当我使用诸如 double getRe() {return re;} ,需要2-3秒。为什么会发生这种情况?

    2 回复  |  直到 8 年前
        1
  •  5
  •   Justin    8 年前

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

    std::function 是一种类类型,就像您可能编写的任何其他自定义类一样。 sizeof(std::function) 不同的实现会有所不同,但合理的值是 24 字节数 1. 。这意味着您将添加 24 字节到 sizeof(Complex) 对于每个成员 std::函数 您要添加,与添加相比 0 每个成员函数的字节数。与…相比 sizeof(double) == 8 在大多数机器上,这是一个很大的开销: Complex 类型可以是 16 字节,但大致为 112 字节。

    此外,每 std::函数 必须初始化成员,可能需要进行堆分配,并调用 std::函数 由于类型擦除,涉及虚拟函数(或等效函数)。这使得编译器很难进行优化,编译器几乎不可能内联函数,而常规成员函数由于其简单程度几乎可以保证是内联的。

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

    1: 此时, sizeof(标准::函数) 实际上是 32 字节, 48 字节,以及 64 打开字节数 libstdc++, libc++, and MSVC's STL respectively


    为了避免每个对象的开销,您可以 static constexpr 成员(至少在C++17中是这样),但是您必须有一个显式 this 参数,它删除了成员函数所具有的所有优良特性。你得写信 Complex::getRe(myComplex) 而不是 myComplex.getRe()

        2
  •  -1
  •   SergeyA    8 年前

    让我为您修复此代码:

    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;
    };
    

    完全相同的结果,更好的可读性,更小的内存占用。去争取吧您的代码对于常量的正确性也是非常糟糕的。

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

    • 您对方法的调用现在是虚拟化的,因此它们不是内联的,您最终会因此受到严重的惩罚
    • 现在您的对象创建/销毁很可能会导致动态内存分配/释放
    • 您的对象没有变大,因此缓存未命中的次数更多