你说你会C++? —— 智能指针

智能指针的设计初衷是:
     C++中没有提供自动回收内存的机制,每次new对象之后都需要手动delete。稍不注意就memory leak。

智能指针可以解决上面遇到的问题。

C++中常见的智能指针包括(共七种):
     std::auto_ptr
     boost::scoped_ptr
     boost::shared_ptr
     boost::intrusive_ptr
     boost::scoped_array
     boost::shared_array
     boost::weak_ptr

    其实,智能指针并不是指针,它仅仅是一个栈对象而已。
在栈对象的生命周期结束时,智能指针调用析构函数释放其管理的堆内存。
所有的智能指针都重载了'operator->'操作符,用来返回其管理对象的引用。从而可以
执行所管理对象的一些操作。

两个方法:
     - get()
          访问智能指针包含的裸指针引用
     - reset()
          若传递参数为空或NULL 则智能指针会释放当前管理的内存。
          若传递参数为一个对象 则智能指针会释放当前管理的内存,管理新传入的对象。

假定有下面这个ManagedObj类。
class ManagedObj
{
public:
    ManagedObj(int val = 0):m_val(val)
    {
        cout<<"Obj : "<<m_val<<endl;
    }

    ~ManagedObj()
    {
        cout<<"~Obj : "<<m_val<<endl;
    }

    void testFun()
    {
        cout<<"testFun : "<<m_info<<endl;
    }

public:
    string m_info;
    int m_val;
};

-> std::auto_ptr

属于STL
在namespace std中
添加头文件 #include <memory>即可使用。
auto_ptr一般用于管理单个堆内存对象。

看下面这个例子:
// std::auto_ptr
void testAutoPtr1()
{
    auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));

    if (atPtr.get())    // 判断智能指针是否为空
    {
        atPtr->testFun();

        atPtr.get()->m_info += " 1st append";    // get() 返回裸指针的引用
        atPtr->testFun();

        (*atPtr).m_info += " 2nd append";        // operator* 返回智能指针管理的对象
        (*atPtr).testFun();
    }
}
运行结果为:

OK 好像没什么问题。

我们接着测试:
void testAutoPtr2()
{
    auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));

    if (atPtr.get())    // 判断智能指针是否为空
    {
        auto_ptr<ManagedObj> atPtr2;

        atPtr2 = atPtr;               // 原因在这行代码
        atPtr2->testFun();
        atPtr->testFun();          // 崩溃在这行代码
    }
}
运行结果为:

调试发现 最后一行代码出bug了。
为什么呢?
其实是atPtr2剥夺了atPtr的内存管理所有权,导致atPtr悬空。

继续测试。
void testAutoPtr3()
{
    auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));

    if (atPtr.get())    // 判断智能指针是否为空
    {
        atPtr.release();
    }
}
运行结果为:

好像又出bug了。
我们并没有看到析构函数被调用的迹象,内存泄漏了。。
(逗我呢 怎么这么多bug?)

别着急 第三个测试函数正确的写法应该是这样的。
void testAutoPtr3()
{
    auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));

    if (atPtr.get())    // 判断智能指针是否为空
    {
        //ManagedObj* temp = atPtr.release();
        //delete temp;

        // 或者
        atPtr.reset();
    }
}

这才是我们想要看到的结果。

所以我们也发现,auto_ptr的release()函数只是让出内存的管理权,并没有真正的释放内存。

总结:
     auto_ptr一般用于管理单个堆内存对象。但是需要注意:
     a. 切记使用 "operator=",万一真用了,就不要再使用旧的对象了。
     b. release()方法不会释放内存 仅仅只是让出所有权。

上面的auto_ptr使用起来确实不是很方便,而且我们还有注意避开它的使用缺陷。
因此就出现了boost中的一些智能指针,下面一一介绍。

-> boost::scoped_ptr

属于boost库
在namespace boost中
添加头文件 #include<boost/smart_ptr.hpp> 即可使用。

关于boost库的安装教程 可参考:

与auto_ptr类似,scoped_ptr也可管理单个堆内存的对象,
但是 它独享所有权,因此也就避免了auto_ptr的缺陷

OK,上代码测试。
// boost::scoped_ptr
void testScopedPtr()
{
	boost::scoped_ptr<ManagedObj> scPtr(new ManagedObj(1, " initialize"));

	if (scPtr.get())
	{
		scPtr->testFun();

		scPtr.get()->m_info += " 1st append";	// get() 返回裸指针的引用
		scPtr->testFun();

		(*scPtr).m_info += " 2nd append";		// operator* 返回智能指针管理的对象
		(*scPtr).testFun();

		//scPtr.release();				// error scoped_ptr 没有成员release
		
		//boost::scoped_ptr<ManagedObj> scPtr2;
		//scPtr2 = scPtr;					// error scoped_ptr<T>::operator=(const scoped_ptr<ManagedObj> &)不可访问
	}
}
运行结果为:

注意注释部分的代码。
scoped_ptr没有release()函数  屏蔽了operator=操作,
因此不会出现auto_ptr中出现的内存泄漏和崩溃问题。
但这也带来了另一个新问题,我们无法复制智能指针。

因此出现了接下来的shared_ptr。

-> boost::shared_ptr

属于boost库
在namespace boost中
添加头文件 #include<boost/smart_ptr.hpp> 即可使用。

由于scoped_ptr不允许赋值 拷贝 独享内存的所有权。
这里的shared_ptr是专门解决智能指针的内存所有权共享这个问题的,
其内部使用了引用计数。

来,测试吧。
// boost::shared_ptr
void testSharedPtr(boost::shared_ptr<ManagedObj> ptr)
{
    ptr->testFun();
    cout<<"shared_ptr use_count: "<<ptr.use_count()<<endl;
}

void testSharedPtr1()
{
    boost::shared_ptr<ManagedObj> shPtr(new ManagedObj(1, " initialize"));

    if (shPtr.get())
    {
        shPtr->testFun();

        shPtr.get()->m_info += " 1st append";    // get() 返回裸指针的引用
        shPtr->testFun();

        (*shPtr).m_info += " 2nd append";        // operator* 返回智能指针管理的对象
        (*shPtr).testFun();
    }

    cout<<"shared_ptr1 use_count: "<<shPtr.use_count()<<endl;
    testSharedPtr(shPtr);
    cout<<"shared_ptr1 use_count: "<<shPtr.use_count()<<endl;
     //shPtr.release(); // error shared_ptr 没有成员release
}
运行结果为:

可以看到,调用testSharedPtr()函数执行了一次复制操作,智能指针内部的引用计数+1。
在该函数调用结束后,引用计数自动-1。

上面介绍的几种智能指针都针对单个对象的内存管理。
其实智能指针也可管理数组,接下来介绍boost::scoped_array和boost::shared_array。

-> boost::scoped_array

属于boost库
在namespace boost中
添加头文件 #include<boost/smart_ptr.hpp> 即可使用。

boost::scoped_array用于管理动态数组,也是独享所有权的。

上代码:
// boost::scoped_array
void testScopedArray()
{
    boost::scoped_array<ManagedObj> scArr(new ManagedObj[2]);        // 动态数组初始化

    if (scArr.get())
    {
        scArr[0].testFun();

        scArr.get()[0].m_info += " [0] 1st append";
        scArr[0].testFun();

        //(*scArr)[0].m_info += " 2st append";    // error scoped_array没有重载operator*
        //(*scArr)[0].testFun();

        //scArr[0].release();                        // error scoped_array 没有成员release

        boost::scoped_array<ManagedObj> scArr2;
        //scArr2 = scArr;                // error operator=不可访问 屏蔽了operator= 禁止拷贝
    }
}
运行结果为:

boost::scoped_array的使用和boost::scoped_ptr大致差不多。
都禁止拷贝 独享所有权。
注意:
      boost::scoped_array没有重载operator*操作符

-> boost::shared_array

属于boost库
在namespace boost中
添加头文件 #include<boost/smart_ptr.hpp> 即可使用。

内部使用了引用计数,解决参数传递和拷贝赋值时的问题。

下面给出代码测试:
// boost::shared_array
void testSharedArray(boost::shared_array<ManagedObj> pArr)
{
    cout<<"shared_arr use_count: "<<pArr.use_count()<<endl;
    boost::shared_array<ManagedObj> pTempArr;
    pTempArr = pArr;
    cout<<"shared_arr use_count: "<<pArr.use_count()<<endl;
}

void testSharedArray1()
{
    boost::shared_array<ManagedObj> shArr(new ManagedObj[2]);

    if (shArr.get())
    {
        shArr[0].testFun();

        shArr.get()[0].m_info += " [0] 1st append";
        shArr[0].testFun();
        shArr[1].testFun();

        shArr.get()[0].m_info += " [1] 1st append";
        shArr[1].testFun();
        //(*shArr)[0].m_info += " [0] 2nd append";    // error 没有重载operator*操作符
    }

    cout<<"shared_arr1 use_count: "<<shArr.use_count()<<endl;
    testSharedArray(shArr);
    cout<<"shared_arr1 use_count: "<<shArr.use_count()<<endl;
}
运行结果为:


-> boost::weak_ptr

属于boost库
在namespace boost中
添加头文件 #include<boost/smart_ptr.hpp> 即可使用。

若我们仅仅关心能否使用对象,而不关心内部的引用计数。
boost::weak_ptr 是 boost::shared_ptr 的观察者(Observer)对象,
意味着boost::weak_ptr只对boost::shared_ptr引用,但是并不更新
其引用计数。被观察的shared_ptr失效后,weak_ptr相应也失效。

上测试代码:
// boost::weak_ptr
void testWeakPtr()
{
    boost::weak_ptr<ManagedObj> wPtr;
    boost::shared_ptr<ManagedObj> shPtr(new ManagedObj(1, "initialize"));

    cout << "testWeakPtr boost::shared_ptr UseCount: " << shPtr.use_count() << endl;
    wPtr = shPtr;
    cout << "testWeakPtr boost::shared_ptr UseCount: " << shPtr.use_count() << endl;
}
运行结果为:

我们发现赋值操作并没有更改引用计数。
boost::weak_ptr更多用于下面这种场合:
     在基类中定义一个weak_ptr,用于观察其子类中的shared_ptr。这样基类只要看自己的weak_ptr
是否为空就知道子类有没对自己赋值,而不影响子类中shared_ptr的引用计数,从而降低复杂度,更好管理对象。

-> boost::intrusive_ptr

属于boost库
在namespace boost中
添加头文件 #include<boost/smart_ptr.hpp> 即可使用。

intrusive_ptr是一种插入式智能指针,其内部没有引用计数,
需要自己加入引用计数,否则会编译错误。


OK 到这儿为止,七种智能指针基本上都大致介绍完了。


参考:

http://blog.csdn.net/xt_xiaotian/article/details/5714477


完整的代码在这里

#include <iostream>
#include <memory>
#include <string>
#include <boost/smart_ptr.hpp>			// add header file

// namespace 
using namespace std;
using namespace boost;

// heap obj class
class ManagedObj
{
public:
	ManagedObj(int val = 0, string info = "")
		:m_val(val), m_info(info)
	{
		cout<<"Obj : "<<m_val<<m_info<<endl;
	}

	~ManagedObj()
	{
		cout<<"~Obj : "<<m_val<<m_info<<endl;
	}

	void testFun()
	{
		cout<<"testFun : "<<m_info<<endl;
	}

public:
	string m_info;
	int m_val;
};

// std::auto_ptr
void testAutoPtr1()
{
	auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));
	
	if (atPtr.get())	// 判断智能指针是否为空
	{
		atPtr->testFun();

		atPtr.get()->m_info += " 1st append";	// get() 返回裸指针的引用
		atPtr->testFun();

		(*atPtr).m_info += " 2nd append";		// operator* 返回智能指针管理的对象
		(*atPtr).testFun();
	}
}

void testAutoPtr2()
{
	auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));

	if (atPtr.get())	// 判断智能指针是否为空
	{
		auto_ptr<ManagedObj> atPtr2;

		atPtr2 = atPtr;
		atPtr2->testFun();
		atPtr->testFun();
	}
}

void testAutoPtr3()
{
	auto_ptr<ManagedObj> atPtr(new ManagedObj(1, " initialize"));

	if (atPtr.get())	// 判断智能指针是否为空
	{
		//ManagedObj* temp = atPtr.release();
		//delete temp;
		
		// 或者
		atPtr.reset();
	}
}

// boost::scoped_ptr
void testScopedPtr()
{
	boost::scoped_ptr<ManagedObj> scPtr(new ManagedObj(1, " initialize"));

	if (scPtr.get())
	{
		scPtr->testFun();

		scPtr.get()->m_info += " 1st append";	// get() 返回裸指针的引用
		scPtr->testFun();

		(*scPtr).m_info += " 2nd append";		// operator* 返回智能指针管理的对象
		(*scPtr).testFun();

		//scPtr.release();				// error scoped_ptr 没有成员release
		
		//boost::scoped_ptr<ManagedObj> scPtr2;
		//scPtr2 = scPtr;					// error scoped_ptr<T>::operator=(const scoped_ptr<ManagedObj> &)不可访问
	}
}

// boost::shared_ptr
void testSharedPtr(boost::shared_ptr<ManagedObj> ptr)
{
	ptr->testFun();
	cout<<"shared_ptr use_count: "<<ptr.use_count()<<endl;
}

void testSharedPtr1()
{
	boost::shared_ptr<ManagedObj> shPtr(new ManagedObj(1, " initialize"));

	if (shPtr.get())
	{
		shPtr->testFun();

		shPtr.get()->m_info += " 1st append";	// get() 返回裸指针的引用
		shPtr->testFun();

		(*shPtr).m_info += " 2nd append";		// operator* 返回智能指针管理的对象
		(*shPtr).testFun();
	}

	cout<<"shared_ptr1 use_count: "<<shPtr.use_count()<<endl;
	testSharedPtr(shPtr);
	cout<<"shared_ptr1 use_count: "<<shPtr.use_count()<<endl;

	//shPtr.release();	// error shared_ptr 没有成员release
}

// boost::scoped_array
void testScopedArray()
{
	boost::scoped_array<ManagedObj> scArr(new ManagedObj[2]);		// 动态数组初始化

	if (scArr.get())
	{
		scArr[0].testFun();

		scArr.get()[0].m_info += " [0] 1st append";
		scArr[0].testFun();

		//(*scArr)[0].m_info += " 2st append";	// error scoped_array没有重载operator*
		//(*scArr)[0].testFun();
		
		//scArr[0].release();						// error scoped_array 没有成员release

		boost::scoped_array<ManagedObj> scArr2;
		//scArr2 = scArr;				// error operator=不可访问 屏蔽了operator= 禁止拷贝
	}
}

// boost::shared_array
void testSharedArray(boost::shared_array<ManagedObj> pArr)
{
	cout<<"shared_arr use_count: "<<pArr.use_count()<<endl;

	boost::shared_array<ManagedObj> pTempArr;
	pTempArr = pArr;
	cout<<"shared_arr use_count: "<<pArr.use_count()<<endl;
}

void testSharedArray1()
{
	boost::shared_array<ManagedObj> shArr(new ManagedObj[2]);

	if (shArr.get())
	{
		shArr[0].testFun();

		shArr.get()[0].m_info += " [0] 1st append";
		shArr[0].testFun();
		shArr[1].testFun();

		shArr.get()[1].m_info += " [1] 1st append";
		shArr[1].testFun();
		//(*shArr)[0].m_info += " [0] 2nd append";	// error 没有重载operator*操作符
	}

	cout<<"shared_arr1 use_count: "<<shArr.use_count()<<endl;
	testSharedArray(shArr);
	cout<<"shared_arr1 use_count: "<<shArr.use_count()<<endl;
}

// boost::weak_ptr
void testWeakPtr()
{
	boost::weak_ptr<ManagedObj> wPtr;
	boost::shared_ptr<ManagedObj> shPtr(new ManagedObj(1, "initialize"));

	cout << "testWeakPtr boost::shared_ptr UseCount: " << shPtr.use_count() << endl;
	wPtr = shPtr;
	cout << "testWeakPtr boost::shared_ptr UseCount: " << shPtr.use_count() << endl;
}

// boost::intrusive_ptr
void testIntrusivePtr()
{
	//boost::intrusive_ptr<ManagedObj> intPtr(new ManagedObj[1], false);	// error 要自己添加引用计数
}

// main function
int main(void)
{
	// -----std::auto_ptr-----
	//testAutoPtr();
	//testAutoPtr2();
	//testAutoPtr3();

	// -----boost::scoped_ptr-----
	//testScopedPtr();

	// -----boost::shared_ptr-----
	//testSharedPtr1();

	// -----boost::scoped_array-----
	//testScopedArray();

	// -----boost::shared_array-----
	//testSharedArray1();

	// -----boost::weak_ptr-----
	testWeakPtr();

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值