为什么这个 lambda 会泄漏内存?

问题描述 投票:0回答:1

我的项目中的代码如下所示:

class ClassA {
    ClassA(int i) : a(i) {};
private:
    int a;
};

struct  ClassB{
    std::shared_ptr<ClassA> classASharedPointer;
};


struct ClassC {
    ClassA* classAPointer;
};


void someFunction(std::vector<ClassB> &vecBs, std::vector<ClassC> &vecCs) {

    const auto toClassC = [](const auto &b) -> ClassC {
        return {b.classASharedPointer.get()};
    };

    std::transform(vecBs.begin(), vecBs.end(), vecCs.begin(),  toClassC);
}

int main() {
    std::vector<ClassB> vecBs(5);
    std::vector<ClassC> vecCs(5);

    someFunction(vecBs, vecCs);

    return 0;
}

当我检查 lambda“toClassC”之前和之后的 VM 大小时,我发现有所增加。我没有看到那段记忆被收回。更糟糕的是,我确实有一种感觉,这个 lambda 是错误的,因为我确实有一种感觉,无论它调用了多少其他对象,它都会采用它看到的第一个对象并对其进行操作。

我该如何解决这个问题?

注意:显然,这不是我正在编写的真正代码(哈!令人震惊)。但我尽力提供一个最小的可重复示例。在上面的这段代码中,我没有看到我在原始项目中看到的虚拟内存大小的增加。

为什么我认为它正在泄漏内存(我可能是错的),因为它每次调用函数时都会为该 lambda 分配空间。记忆永远不会被回收。 AFAIK,这不应该发生。并且 lambda 的空间只能保留一次。但我看到的是,例如,如果

main()
调用
someFunction()
两次,我将看到该 lambda 的两次内存分配。

c++ lambda
1个回答
0
投票

您显示的代码中没有内存泄漏。

唯一动态分配的内存是为

std::vector
元素分配的,当
vector
main()
末尾超出范围时,该内存将自动回收。
someFunction()
toClassC
都没有分配任何可能泄漏的动态内存。

当我检查 lambda“toClassC”之前和之后的 VM 大小时,我发现有所增加。而且我没有看到记忆被回收。

toClassC
没有动态分配内存。

更糟糕的是,我确实有一种感觉,这个 lambda 是错误的,因为我确实有一种感觉,无论调用了多少其他对象,它都会采用它看到的第一个对象并对其进行操作。

这是不正确的。

std::transform()
将为
vecBs
中的每个元素调用 lambda。 当第一次调用 lambda 时,其
b
参数将引用第一个
ClassB
对象,然后第二次调用将引用第二个
ClassB
对象,依此类推。
std::transform()
基本上只是在指定范围内的美化循环。

我该如何解决这个问题?

没有什么需要修复的,因为这里没有任何东西损坏。

为什么我认为它正在泄漏内存(我可能是错的),因为它每次调用函数时都会为该 lambda 分配空间。

您使用的是非捕获 lambda,因此它没有内部数据成员可供分配内存。 它基本上是一个空物体。 但它仍然是一个对象(即,它可以传递)。而且由于它不是动态分配的,因此它不会泄漏。

你的代码大致相当于这个:

struct lambda {
    ClassC operator()(const ClassB &b) {
        ClassC c{b.classASharedPointer.get()};
        return c;
    };
};

void someFunction(std::vector<ClassB> &vecBs, std::vector<ClassC> &vecCs) {
    const lambda toClassC;
    auto first1 = vecBs.begin(), last1 = vecBs.end();
    auto d_first = vecCs.begin();
    for (; first1 != last1; ++d_first, ++first1) {
        *d_first = toClassC.operator()(*first1);
    }
}

简而言之,对于

ClassB
中的每个
vecBs
元素,您将其
ClassA*
指针分配给
ClassC
中相应的
vecCs
元素。仅此而已。

内存永远不会被回收。 AFAIK,这不应该发生。

没有动态分配的内存需要回收。

并且 lambda 的空间只能保留一次。

这是不正确的。

但是我看到的是,例如,如果 main() 调用 someFunction() 两次,我将看到该 lambda 的两次内存分配。

每次调用

someFunction()
时,它都会在调用堆栈上获取一个新帧来保存其局部变量。当
someFunction()
退出时,该帧将被回收。
toClassC
someFunction()
的局部变量,与任何其他局部变量没有什么不同。

© www.soinside.com 2019 - 2024. All rights reserved.