lambda信号槽机制,提问:信号发送者是全局的,是否可以变成局部的,如果变成局部的是否有内存增长?
答:不要用局部的,基本上没有任何价值,除非,你本身就打算把它作为bug存在!
证明:局部的,代表,外部不可用,其次,循环再次进入,将不是同一个东西!
那么lambda槽函数不是同一个东西,类似于局部变量,那么是不是不会导致内存增长?
一定会有内存增长,因为,每一次信号槽绑定,尤其是在时间QTimer上,如果从全局入手,可以发现,在没有限制条件的情况下,再次绑定的信号槽,lambda槽函数将会以新建的方式另造一个。所以,造成内存增长的其实是lambda槽函数!
那么lambda函数,难道从一开始就是独立存在,不可回收的资源吗?是不是就像枚举一样?
lambda的本质是“闭包对象”
闭包对象
在C++中,闭包对象(Closure Object)是编译器为lambda表达式自动生成的一个匿名类(unnamed class)的实例,它封装了lambda的逻辑代码以及捕获的外部变量。
闭包对象的生命周期:
栈分配
若闭包对象未被延长生命周期(如未存入容器或跨作用域传递),它会在当前作用域结束时自动销毁,成员变量也随之释放。
{
int x = 10;
auto lambda = [x]() { /* ... */ }; // 闭包对象在栈上,作用域结束时销毁
}
堆分配
若闭包对象被存入动态容器(如 std::function)或跨线程传递,可能需要手动管理内存(或依赖智能指针)。
std::function<void()> func;
{
int x = 10;
func = [x]() { /* ... */ }; // 闭包对象可能被拷贝到堆上(由std::function管理)
}
func仍可调用,闭包对象由std::function管理生命周期。
这也就侧面证明了,当使用QTimer类成员对象或全局实例对象,绑定lambda槽函数,有内存泄露的风险,尤其是面对循环程序。
匿名类(unnamed class)
lambda类:
- 重载了 operator(),使其可被调用(即实现函数功能)。
- 根据捕获方式(值捕获、引用捕获)将外部变量作为成员变量或"引用存储"。
案例1:
int x = 10;
auto lambda = [x](int y) { return x + y; }; // 闭包对象
等价于
class __lambda_unique_name { // 匿名类(实际名称由编译器生成)
private:
int captured_x; // 值捕获的变量x成为成员变量
public:
__lambda_unique_name(int x) : captured_x(x) {} // 构造函数初始化捕获的变量
int operator()(int y) const { return captured_x + y; } // 重载operator()
};
案例2

输出结果

引用存储
在C++中,引用存储(Reference Storage)指的是通过引用(Reference)“捕获或传递”变量时,实际存储的是变量的内存地址(或别名),而非变量本身的副本。
3429

被折叠的 条评论
为什么被折叠?



