C++中的智能指针(Smart Pointer)

       当C++中类的成员为指针类型时,对该类的对象进行拷贝或者赋值时,多个对象副本的指针成员就会指向同一块动态申请的内存,如何来释放指针指向的内存将成为一个难以解决的问题:

class A
{
public:
     A()
     {
        p = new int[5];
     }

     ~A()
     {
        delete p;
     }
    void Release()
    {
        delete p;
    }
private: 
     int count;
     int* p;
}

int main()
{
    A a1;
    A a2(a1);
}

       如果直接在析构中释放,当第二个对象被析构时,由于之前一个对象已经释放了内存,再delete就会出错,而如果在析构中不释放p指向的内存,将会导致内存泄露。如果由一个对象显式Release掉内存,另一个对象中的指针将成为“野指针”。因此需要一种策略来决定何时指针p被释放,解决的方法就是引用计数,引用计数的基本原则是所有的对象中看到的计数值必须是同步的,计数为0时说明没有其它对象正在使用这段内存了,该对象就可以用Release释放了。

      如果直接把一个计数器count放到A中,显然是不行的,在上面的例子中,可以通过编码保证a1 a2中的count值是一致的,但如果再有一个对象由a2拷贝得到: A a3(a2) ,那么a1中的count值将无法被同步(C++ Primer中举的例子) 

      C++ Primer中给出的解决方案为,用一个单独的对使用者不可见的类ActualPointer来封装指针和引用计数,将暴露给使用者的类PointerWrapper声明为其友元类:

      

class ActualPointer
{
	 friend class PointerWrapper;
private:
	 int *p;
	 int count ;
public:
	ActualPointer(int *value):p(value)
	{
		count = 1;
	}

	~ActualPointer()
	{
		delete p;
	}
};

class  PointerWrapper
{
private:
	ActualPointer *ptr;
public:
	PointerWrapper(int *value)
	{
		ptr = new ActualPointer(value);
	}

	~PointerWrapper()
	{
		ptr->count--;
		if(ptr->count == 0)
			delete ptr;
	}

	PointerWrapper(const PointerWrapper &pw):ptr(pw.ptr)
	{
		pw.ptr->count++;
	}

};
int main()
{
        int* value = new int[5];
	PointerWrapper pw(value);
	PointerWrapper pw2(pw);
        return 0;
}

        可以看出,当对PointerWrapper类的对象进行拷贝时,由于多个拷贝中使用的是同一个ActualPointer对象,可以保证count的值是一致的,而当一个PointerWrapper对象被析构时,会判断其指向的ActualPointer中的计数值,为0时才释放实际的内存,如果不为0则不会导致实际的指针被释放,使用时也不用显示释放内存,当PointerWrapper析构时会自动进行判断并释放。

       这种方法不错,但我个人觉得还是挺难以理解的,其实还有另一种更简单的方法只需要在最初的版本上稍加改动即可,之前将count值直接放入对象中不可行的原因是各个对象中的count值无法同步,因此只需要将count的类型修改为int * 即可,每次拷贝时各个副本中count指针指向的是同一个int,就可以保证计数器的值是同步的了。

   

class SmartPointer2
{
private:
	int *value;
	int* count;
public:
	SmartPointer2(int *v):value(v),count(new int)
	{
		*count = 1;
	}

	SmartPointer2(const SmartPointer2 &sp):value(sp.value),count(sp.count)
	{
		++*count;
	}


	~SmartPointer2()
	{
		--*count;
		if(*count == 0)
		{
			delete value;
			delete count;
		}
	}
};
int main()
{
	int* value = new int[5];
	SmartPointer2 sp(value);
	SmartPointer2 sp2(sp);
        return 0;
}

  

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值