类中有指针成员时,如何避免重复释放
在下面的代码中,类A保存有1个指针,并且理所当然的在构造函数中分配内存,析构中释放内存,但会发生重复释放的问题。
原因:编译器自动生成如下的拷贝构造(析构函数不影响拷贝操作的自动生成,只会影响移动操作的自动生成)
解决方法1:显式的删除拷贝构造函数,然后使用时传引用
#include <iostream>
using namespace std;
struct A
{A(){cout<<"默认构造"<<endl;p = malloc(1);}//A(const A& that):p(that.p){// cout<<"拷贝构造"<<endl;//}~A(){free(p);cout<<"析构"<<endl;}void *p;
};
int main(int argc, char *argv[])
{A a;//默认构造 a.p = malloc(1)A b(a);//拷贝构造 b.p = a.p//析构 free(b.p)//析构 free(a.p)return 0;
}
定义了移动构造,就记得析构函数里自己判空
A(A&& that){p = that.p;that.p = nullptr;cout<<"移动"<<endl;
}
~A(){if (p){free(p);cout<<"析构"<<endl;}
}
-
解决方法2:
拷贝构造和移动构造函数都删除掉,传参的时候用unique_pointer包装一下,因为独占指针是可以移动的。此时指针指向的资源不可移动,指针可以移动#include <iostream> #include <memory>using namespace std;struct A {A(){p = malloc(1);}A(const A& that) = delete;A(A&& that) = delete;~A(){free(p);}void *p; };void fun(std::unique_ptr<A> x){ }int main(int argc, char *argv[]) {auto a_p = make_unique<A>();fun(move(a_p));return 0; }
-
区分
A a1; A a2 = a1;//拷贝构造 a1 = a2;//拷贝赋值
-
解决方法3:
实际上只需要删除移动构造,就会默认不生成 移动赋值、拷贝构造、拷贝赋值因为:移动构造和移动赋值相互影响 移动操作和拷贝操作相互影响
同理,只需要删除移动赋值,其余3个也就不会生成了A(const A& that) = delete;//拷贝构造 A(A&& that) = delete;//移动构造 A &operator=(A && that) = delete;//移动赋值 A &operator=(const A& that) = delete;//拷贝赋值
-
解决方法4
把该类写在类中,使用智能指针来管理。当然也可以不写在类中#include <iostream> #include <memory> using namespace std; struct A { private:struct A_Imp{A_Imp(){p = malloc(1);cout<<"malloc"<<endl;}~A_Imp(){free(p);cout<<"free"<<endl;}void otherfun(){cout<<"xxxx"<<endl;}void* p; };shared_ptr<A_Imp> impl; public:A(){impl = make_shared<A_Imp>();}A_Imp* operator->(){return impl.get();} };int main(int argc, char *argv[]) {A a1;A a2(a1);a1->otherfun();return 0; }
-
智能指针的深拷贝怎么写
对智能指针取*然后重新构造一个
A(const A &that){impl = make_shared<A_Imp>(*that.impl); }