shared_ptr https://floating.io/2017/07/lambda-shared_ptr-memory-leak/
lambda和shared_ptr搭配有可能会出现内存泄漏,需要注意传入的参数,lambda里如果捕获shared_ptr,由于lambda的特殊性,会产生一个数据结构存放shared_ptr,当functional与lambda或者functional之间拷贝时,shared_ptr对象会值传递,导致引用计数增加,出现内存泄漏。可以通过weak_ptr避免。
当lambda里没有捕获时,lambda表现为一个指针
typedef void(*fun)(int); fun f = [](){}; //当lambda没有捕获时,为一个指针当lambda捕获参数时,lambda里有一个该参数,且有一个函数指针 需要注意的是auto a = [] ( ){}与function< void> a = [] (){}中,a的类型是不一致的。如下图所示,内存排布不尽相同。但有捕获参数时,捕获的值都放在内存的前列
lambda: std::function<int(int)> meta_add(int x) { auto add = [x](int y) { return x + y; }; return add; } 用struct实现lambda,有一个int,有一个functor struct lambda { lambda(int x) : x(x) { } int operator ()(int y) { return x + y; } private: int x; }; std::function<int(int)> meta_add(int x) { lambda add(x); return add; }
line1里用的引用捕获,use_count不增加,通过debug发现,
捕获引用 shared_ptr时,lambda形成一个指针指向shared_ptr(经过测试,其他类型传入后,lambda的大小也是8)非引用捕获时,lambda对象中,形成包含该数据类型的变量line1里=拷贝的时候,拷贝的指针,use_count不增加,lambda结束时,应该是delete创建的普通指针如果line1是std::function<void()> fa = obj{};line2 = 拷贝时,值捕获,use_count+1,拷贝use_count再加1,lambda结束,use_count-1 = 2 #include <iostream> #include <functional> #include <memory> int main() { std::shared_ptr<int> obj = std::make_shared<int>(1); std::cout<<"1: "<<obj.use_count()<<std::endl; auto &fa = obj; int i= 1; int j= 2; auto fd = [&obj,i](){}; //line 1 //std::function<void()> fa = [obj](){}; std::cout<<sizeof(obj)<<sizeof(fa)<<sizeof(fd)<<sizeof(i)<<std::endl; std::cout<<"2: "<<obj.use_count()<<std::endl; std::function<void()> fd2; fd2 = [obj](){}; //line 2 std::cout<<"3: "<<obj.use_count()<<std::endl; }输出结果如下:
lxz@lxz-VirtualBox:~/liuxz/testmake$ ./main 1: 1 1616244 //注意24是8+(4)+12,内存对齐 2: 1 3: 2背景:希望在on_complete时候,调用complete_callback回调函数,回调函数中要调用clean_something_up函数
如下所示,代码中使用了三种on_complete
lambda捕获shared_ptr,指向this,在函数体中调用clean_something_up 1 void on_complete(callback cb){complete_callback = cb;} //my_class的函数 2 std::shared_ptr<my_class> obj = std::make_shared<my_class>(); 3 obj->on_complete([obj]() {obj->clean_something_up();});如下代码中,
#include <iostream> #include <functional> #include <memory> //#include <boost/enable_shared_from_this.hpp> class my_class :public std::enable_shared_from_this<my_class>{ // ... public: typedef std::function<void()> callback; void on_complete(std::shared_ptr<my_class> &ab,callback cb) { //cb = lambda(一个shared_ptr,一个函数指针),调用的move,不改变use_count的值 std::cout<<"++++++++++"<<ab.use_count()<<std::endl; // use_count = 2 complete_callback = cb; // use_count+1 = 3 std::cout<<"_________"<<ab.use_count()<<std::endl; complete_callback(); std::cout<<"???????????"<<ab.use_count()<<std::endl; // on_complete里,函数结束cb析构,use_count-1= 2,main函数结束,obj被析构,use_count -1 = 1,obj指向的对象没有被析构,即complete_callback 还在,产生内存泄漏 } void on_complete(callback cb) { complete_callback = cb; complete_callback();} //这里functional 拷贝的是weak_ptr,所以不修改use_count计数 void on_complete() { complete_callback = std::bind(&my_class::clean_something_up,shared_from_this()); //bind是万能引用,shared_from_this(),use_count会+1 ,但是由于bind是万能引用,实际是右值引用,利用了move构造,swap //调用顺序:1.shared_from_this ----2.bind(_Func&& __f, _BoundArgs&&... __args) ----3.operator=(_Functor&& __f),所以use_count在shared_from_this导致+1 =2 后,不再变化 std::cout<<"1 shared_from_this: "<<shared_from_this().use_count()<<std::endl; // 3 //需要注意,shared_from_this函数里,return shared_ptr<_Tp>(this->_M_weak_this) // shared_ptr<_Tp> shared_from_this(){ return shared_ptr<_Tp>(this->_M_weak_this); } 使用weak_ptr构造的shared_ptr,计数+1,但是是临时对象,生命周期 //结束后会,obj1对象被析构,use_count减一,但是use_count=1, 对象不会被析构,产生内存泄漏 std::cout<<"2 shared_from_this: "<<shared_from_this().use_count()<<std::endl; // 3 complete_callback();} void clean_something_up(){std::cout<<"helloworld"<<std::endl;} private: callback complete_callback; // ... }; int main() { // ... std::shared_ptr<my_class> obj = std::make_shared<my_class>(); std::shared_ptr<my_class> obj1 = std::make_shared<my_class>(); std::shared_ptr<my_class> obj2 = std::make_shared<my_class>(); int i= 3; int j= 5; int k = 7; int g =9; std::function<void()> f1 = [i,j,k,g](){std::cout<<"helloworld"<<std::endl;}; std::cout<<*((int*)&f1+3)<<std::endl; std::cout<<obj.use_count()<<std::endl; obj->on_complete(obj,[obj]() { obj->clean_something_up(); std::cout<<obj.use_count()<<std::endl; }); obj1->on_complete(); //executor->submit(obj); obj2->on_complete([wp = std::weak_ptr<my_class>(obj2)](){ //这里使用weak_ptr,lambda里拷贝不增加计数 std::cout<<"1 weak_ptr : "<<wp.use_count()<<std::endl; auto obj = wp.lock(); // lock获取weak_ptr所构造的shared_ptr,use_count+1 = 2 std::cout<<"2 weak_ptr : "<<wp.use_count()<<std::endl; if(obj) obj->clean_something_up(); //函数结束,obj析构,计数-1 = 1,main函数结束,obj2计数-1 = 0,不产生内存泄漏 }); return 0; }运行结果如下
lxz@lxz-VirtualBox:~/liuxz/testmake$ ./main 9 1 ++++++++++2 _________3 helloworld 3 ???????????3 1 shared_from_this: 3 2 shared_from_this: 3 helloworld 1 weak_ptr : 1 2 weak_ptr : 2 helloworld待续 https://www.cnblogs.com/Aion/p/3449756.html https://blog.csdn.net/goldenhawking/article/details/70589476 https://www.zhihu.com/question/22444939/answer/108943396
#include<iostream> #include<functional> #include<memory> using namespace std; std::function<void()> g_f; class Foo : public std::enable_shared_from_this<Foo> { public: Foo(int i): p(i){} int p = 2; std::function<void()> on_complete() { return [self = shared_from_this()]() { cout<<"2:"<<(self->p) <<endl; }; } }; int main() { { shared_ptr<Foo> foo= make_shared<Foo>(1); cout<<"addr of foo:"<<foo.get()<<endl; g_f=foo->on_complete(); cout<<"addr of g_f:"<<(*((shared_ptr<Foo>*)(&g_f))).get()<<endl; cout<<"1:"<<foo.use_count()<<endl; } g_f(); }