内存泄露一直是C++程序员头疼的问题。下面就简单理解下C++智能指针。
智能指针 是存储指向动态分配对象指针的类。 目的是能够自动正确的销毁内存,防止内存泄露。
通
用的实现技术是使用引用计数(reference count),将一个计数器与类指向的对象相关联。引用计数跟踪该类有多少个对象共享同一指针
创建一个类的对象时, 初始化指针并且将引用计数置为1;
当一个对象作为另一个对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相关的引用计数。
对一个对象进行赋值时,赋值操作符减少左操作数的引用计数,如引用计数为0, 删除对象, 释放对象指向的内存
并增加右操作符所指对象的引用计数。
调用析构函数时,减少引用计数, 如果引用计数为0, 删除对象, 释放对象指向的内存
设计思路:
由于需要一个引用计数和一个指针动态内存,将他们封装为一个类
定义一个Uptr类,成员函数为引用计数和指针。 实现构造函数, 析构函数, 拷贝构造函数和赋值运算符重载。
设计一个管理类HasPtr, 管理这个Uptr类的引用计数和指针,将HasPtr声明为Uptr类的友元类。即只有HasPtr可以访问为Uptr类。
用2个类实现的好处是 解耦合,增加智能指针的可扩展性,引用计数和指针是不变的, 智能指针的管理是可变的, 将可变的和不变的逻辑分离出来。
- class Uptr
- {
- /*Uptr has private member, only HasPtr class can access it*/
- friend class HasPtr;
- private:
- Uptr(int *p):m_ptr(p),m_useNum(1)
- {
- cout<< "Uptr constructor called" << endl;
- }
- ~Uptr()
- {
- if(NULL!=m_ptr)
- {
- delete []m_ptr;
- m_ptr = NULL;
- }
- cout << "Uptr destructor called" << endl;
- }
- Uptr(const Uptr& o)
- {
- m_ptr = o.ptr;
- }
- Uptr& operator=(const Uptr& o)
- {
- if (&o == this)
- {
- return;
- }
- if (m_ptr != NULL)
- {
- delete []m_ptr;
- }
- //shallow copy
- m_ptr = o.m_ptr;
- }
- private:
- int* m_ptr;
- int m_useNum;
- };
下面是实现HasPtr 管理类
- class HasPtr
- {
- public:
- HasPtr(int *p):m_ptr(new Uptr(p))
- {
- cout << "HasPtr constructor called!" << "use=" <<
- m_ptr->m_useNum << endl;
- }
- HasPtr(const HasPtr& o)
- {
- m_ptr = o.m_ptr;
- /*add the useNum when copy*/
- ++m_ptr->m_useNum;
- cout << "HasPtr copy constructor called!" << "use=" <<
- m_ptr->m_useNum << endl;
- }
- HasPtr& operator=(const HasPtr& o);
- ~HasPtr()
- {
- /*delete the useNum when destructor*/
- if (--m_ptr->m_useNum == 0)
- {
- delete m_ptr;
- }
- cout << "HasPtr distructor called!" << "use=" <<
- m_ptr->m_useNum << endl;
- }
- void set_ptr(int *p)
- {
- if (p == NULL)
- {
- delete m_ptr;
- }
- m_ptr->m_ptr = p;
- }
- int* get_ptr() const
- {
- return m_ptr->m_ptr;
- }
- private:
- Uptr* m_ptr;
- };
- HasPtr& HasPtr::operator=(const HasPtr& o)
- {
- cout << "operator= called" << endl;
- if (&o == this)
- {
- return *this;
- }
- ++o.m_ptr->m_useNum;
- /*release the memory if it is neccessary*/
- if (--m_ptr->m_useNum == 0)
- {
- delete m_ptr;
- }
- m_ptr = o.m_ptr;
- return *this;
- }
其中有几个需要注意的地方:
赋值运算符重载要考虑 自己赋值给自己的特殊情况, 一个智能指针类对象给另一个智能指针类对象赋值时, 赋值操作符减少左操作数的引用计数,如引用计数为0, 删除对象, 释放对象指向的内存并增加右操作符所指对象的引用计数。
全部程序:
- /*
- *describe: realize smart point, keep improve
- */
- #include <iostream>
- #include <string.h>
- using namespace std;
- /*use two class realize the function. high cohesion and low coupling*/
- class Uptr
- {
- /*Uptr has private member, only HasPtr class can access it*/
- friend class HasPtr;
- private:
- Uptr(int *p):m_ptr(p),m_useNum(1)
- {
- cout<< "Uptr constructor called" << endl;
- }
- ~Uptr()
- {
- if(NULL!=m_ptr)
- {
- delete []m_ptr;
- m_ptr = NULL;
- }
- cout << "Uptr destructor called" << endl;
- }
- Uptr(const Uptr& o)
- {
- m_ptr = o.ptr;
- }
- Uptr& operator=(const Uptr& o)
- {
- if (&o == this)
- {
- return;
- }
- if (m_ptr != NULL)
- {
- delete []m_ptr;
- }
- //shallow copy
- m_ptr = o.m_ptr;
- }
- private:
- int* m_ptr;
- int m_useNum;
- };
- class HasPtr
- {
- public:
- HasPtr(int *p):m_ptr(new Uptr(p))
- {
- cout << "HasPtr constructor called!" << "use=" <<
- m_ptr->m_useNum << endl;
- }
- HasPtr(const HasPtr& o)
- {
- m_ptr = o.m_ptr;
- /*add the useNum when copy*/
- ++m_ptr->m_useNum;
- cout << "HasPtr copy constructor called!" << "use=" <<
- m_ptr->m_useNum << endl;
- }
- HasPtr& operator=(const HasPtr& o);
- ~HasPtr()
- {
- /*delete the useNum when destructor*/
- if (--m_ptr->m_useNum == 0)
- {
- delete m_ptr;
- }
- cout << "HasPtr distructor called!" << "use=" <<
- m_ptr->m_useNum << endl;
- }
- void set_ptr(int *p)
- {
- if (p == NULL)
- {
- delete m_ptr;
- }
- m_ptr->m_ptr = p;
- }
- int* get_ptr() const
- {
- return m_ptr->m_ptr;
- }
- private:
- Uptr* m_ptr;
- };
- HasPtr& HasPtr::operator=(const HasPtr& o)
- {
- cout << "operator= called" << endl;
- if (&o == this)
- {
- return *this;
- }
- ++o.m_ptr->m_useNum;
- /*release the memory if it is neccessary*/
- if (--m_ptr->m_useNum == 0)
- {
- delete m_ptr;
- }
- m_ptr = o.m_ptr;
- return *this;
- }
- /*for test*/
- void test_func()
- {
- int* pValue = new int(10);
- int* pValue1 = new int(20);
- if (NULL == pValue)
- {
- return;
- }
- HasPtr ptr1(pValue);
- HasPtr ptr2(ptr1);
- HasPtr ptr3 = ptr1;
- HasPtr ptr4(pValue1);
- ptr4 = ptr1;
- cout << endl;
- }
- int main(int argc, char** argv)
- {
- test_func();
- return 0;
- }