C++应用系列:用智能指针shared_ptr中引用计数思想进行动态内存管理
2018-03-15 16:02
826 查看
如果在类的定义中不自己定义默认拷贝赋值构造函数与析构函数,编译器会自动创建合成函数,在初始化时使用类内初始值或默认值初始化成员。
编译器自动生成提供的默认拷贝构造函数是浅拷贝,所谓浅拷贝,则是简单将成员进行赋值操作,如果成员中存在指针或引用时,执行浅拷贝则只是将指针或引用赋值,而具体指向的是同一内存空间,在修改值时会出现意想不到的问题,而且,最重要是在析构时同一内存单元重复释放两次。
当我们在堆中存储动态分配的对象,即使用动态内存时,通常容易出现3种错误:
1.忘记delete之前new的内存,即内存泄漏。
2.使用空悬指针访问释放掉的内存。
3.重复释放同一内存单元。
智能指针shared_ptr中有一个名为引用计数的计数器,记录指向某同块内存的shared_ptr,当计数器为0时自动调用析构函数释放内存,这样能够有效避免上述问题,具体用法网上书上较多资料,此处不赘述。
当类中存在动态内存时,可以自己定义类的拷贝构造函数以及拷贝赋值运算符,进行深拷贝。使每个对象管理独立的内存,并在析构中释放该内存。
C++基础系列:深拷贝浅拷贝函数与拷贝赋值操作符
也可以利用引用计数的思路进行动态内存的管理,多个指针指向相同的内存块,但是只有在最后一个指针销毁时,才释放该内存。
编译器自动生成提供的默认拷贝构造函数是浅拷贝,所谓浅拷贝,则是简单将成员进行赋值操作,如果成员中存在指针或引用时,执行浅拷贝则只是将指针或引用赋值,而具体指向的是同一内存空间,在修改值时会出现意想不到的问题,而且,最重要是在析构时同一内存单元重复释放两次。
当我们在堆中存储动态分配的对象,即使用动态内存时,通常容易出现3种错误:
1.忘记delete之前new的内存,即内存泄漏。
2.使用空悬指针访问释放掉的内存。
3.重复释放同一内存单元。
智能指针shared_ptr中有一个名为引用计数的计数器,记录指向某同块内存的shared_ptr,当计数器为0时自动调用析构函数释放内存,这样能够有效避免上述问题,具体用法网上书上较多资料,此处不赘述。
当类中存在动态内存时,可以自己定义类的拷贝构造函数以及拷贝赋值运算符,进行深拷贝。使每个对象管理独立的内存,并在析构中释放该内存。
C++基础系列:深拷贝浅拷贝函数与拷贝赋值操作符
//class Rect //带有int *scale成员 Rect(T a, T b) :m_lenth(a), m_width(b) { scale = new int; } Rect(const Rect<T> &rect) { cout << "重载拷贝" << endl; scale = new int; *scale = rect.getScale(); m_lenth = rect.getLength(); m_width = rect.getWidth(); } ~Rect() { delete scale; } Rect<T>& operator=(const Rect<T> &rect) { cout << "重载赋值" << endl; scale = new int; *scale = rect.getScale(); m_lenth = rect.getLength(); m_width = rect.getWidth(); return *this; }
也可以利用引用计数的思路进行动态内存的管理,多个指针指向相同的内存块,但是只有在最后一个指针销毁时,才释放该内存。
//定义一个矩形类模板 //模板中含有计算矩形面积和周长的成员函数 //数据成员为矩形的长和宽。 #include <iostream> using namespace std; template <typename T> class Rect { public: Rect(T a,T b):scale(new int(0)), //每个对象直接构造时new内存 ref_cnt(new size_t(1)) { cout << "构造" << endl; } Rect(const Rect<T> &rect) :scale(rect.scale), //拷贝与赋值时不开辟新内存,指向同一块内存 ref_cnt(rect.ref_cnt) { cout << "重载拷贝" << endl; ++*ref_cnt; } ~Rect() { if(--*ref_cnt == 0) //每个对象析构后引用数-1,为0则释放内存 { delete ref_cnt; delete scale; } } Rect<T>& operator=(const Rect<T> &rect) { cout << "重载赋值" << endl; ++*ref_cnt; //等号右侧赋值后引用数+1 if (--*ref_cnt == 0) //等号左侧赋值后引用数-1 { delete ref_cnt; delete scale; } ref_cnt = rect.ref_cnt; scale = rect.scale; return *this; } void setScale(int _scale) { *scale = _scale; } private: int *scale; size_t *ref_cnt; }; template <typename T> Rect<T> doNothing(const Rect<T> &rect) { return rect; } int main(void) { Rect<int> rect(0,0);//构造 rect.setScale(1); Rect<int> rect2(0,0);//构造 rect2 = rect; //赋值 Rect<int> rect3 = rect; //调用拷贝构造函数 rect.setScale(2); Rect<int> rect4 = doNothing(rect);//拷贝 Rect<int> rect5(0, 0);//先构造,调用带参数构造函数 rect5 = doNothing(rect);//调用拷贝构造函数,再调用拷贝赋值 return 0; }
相关文章推荐
- 实战c++中的智能指针unique_ptr系列--通过unique_ptr对shared_ptr进行初始化
- 实战c++中的智能指针unique_ptr系列--通过unique_ptr对shared_ptr进行初始化
- 智能指针shared_ptr引用计数工作原理
- boost库在工作(9)引用计数的智能指针shared_ptr之二
- boost库在工作(9)引用计数的智能指针shared_ptr之二
- C++智能指针(三):weak_ptr--解决shared_ptr循环引用问题
- 引用计数的智能指针——sharedptr的模拟实现
- c++:分析智能指针shared_ptr存在的循环引用的缺陷
- boost库在工作(8)引用计数的智能指针shared_ptr之一
- boost库在工作(9)引用计数的智能指针shared_ptr之二
- boost库在工作(10)引用计数的智能指针shared_array
- 说说C++智能指针(1): 关于shared_ptr
- std::auto_ptr boost::shared_ptr智能指针的应用
- C++智能指针shared_ptr剖析
- C++智能指针:auto_ptr、shared_ptr、weak_ptr等
- C++:智能指针-TR1的shared_ptr和weak_ptr使用介绍
- 实战c++中的智能指针unique_ptr系列-- unique_ptr的operator=、operator bool、reset、swap、get等介绍
- C++中的资源管理(一):构造自己的auto_ptr与shared_ptr智能指针
- C++ 引用计数技术及智能指针的简单实现
- 实战c++中的智能指针unique_ptr系列-- unique_ptr与lambda的错误结合(尤其是捕获lambda中的unique_ptr)