简单的C++智能指针
2009-08-01 20:53
465 查看
本文链接:简单的C++智能指针
从书上看到了一个C++智能指针的例子,感觉不错,小改进了下,放出来。
智能指针的大意是:对普通的类(假设C)指针进行包装,内部维护一个引用计数。程序中只要使用智能指针包装类(假设SafeC)就行了。用的时候只用new C(), 然后把其给包装类进行构造,然后就随便用啦,不用担心C的析构问题了。
众所周知,C++中如果需要动态申请内存的话,就一定要释放。可是不是所有new出来的对象都能明确的知道该在哪里释放。释放的话,不知道在哪里释放才好,总不能某处正在使用着呢,就给delete了;不释放的话,就是传说中的内存泄漏。
所以,智能指针(好像也有叫安全指针的)的作用就显出来了。把一个申请来的对象指针,扔给智能指针去管理。智能指针会在对其所有引用都释放后,把内部管理的指针所指向的对象删除。使用起来的效果就像.Net和Java的引用一样。不过垃圾回收的机理应该和这个有些不同。
智能指针只使用值传递就可以,没有必要使用指针传递或引用传递,虽然效率高一点点。需要注意的是,智能指针就不要去new了,不然就失去其本来的意义了。
代码我改动了不少,还添加了测试代码。书上的代码只有很简单的非泛型的SafeC类。各种优缺点大家自己体会吧。(和Java或者是.Net对比一下,发现了这样写的优点了吧~)
另外说明一点:这个代码是没法在普通的C++环境下编译的,因为用的是C++.Net……用的.Net的控制台输出。大家把所有的输出代码删掉或改用C++的输出流就可以运行了(不要告诉我你看不出来哪个是.Net的东西啊……)。
另外:这个安全指针不是线程安全的,多线程中跨线程使用会出问题,需要添加线程锁。加锁一种可能的做法是:再维护一个锁对象的指针,在所有能接收到C新实例的指针的构造器中进行初始化,并与C的指针一同析构,在所有可能改变引用计数的地方进行线程同步,如构造器,赋值操作符,析构器。
代码:(自己写主函数)
相关测试代码:
输出:
In Singleton's Constructor.
>>>>> object in stack test:
! in C1.C1, id: 1
reference count in SafeC.constructor: 1
s1
reference count in SafeC.constructor: 2
s2
rs3
reference count in SafeC.constructor: 3
invoke: s4->Func()
! in C1.f, id: 1
<<<<< end stack test.
>>>>> object in heap test:
ps5
! in C1.C1, id: 2
reference count in SafeC.constructor: 1
rs6
! in C1.C1, id: 3
reference count in SafeC.constructor: 1
s7
reference count in SafeC.constructor: 2
delete ps5
in SafeC.destructor, before excute, count: 2
and the instance's id: 2
<<<<< end heap test.
>>>>> method return value test:
! in C1.C1, id: 10
reference count in SafeC.constructor: 1
<<<<< end method return value test.
in SafeC.destructor, before excute, count: 1
and the instance's id: 10
and delete the pointer to instance !! instance's id: 10
! in C1.~C1, id: 10
in SafeC.destructor, before excute, count: 1
and the instance's id: 2
and delete the pointer to instance !! instance's id: 2
! in C2.~C2, id: 2
! in C1.~C1, id: 2
in SafeC.destructor, before excute, count: 3
and the instance's id: 1
in SafeC.destructor, before excute, count: 2
and the instance's id: 1
in SafeC.destructor, before excute, count: 1
and the instance's id: 1
and delete the pointer to instance !! instance's id: 1
! in C1.~C1, id: 1
从书上看到了一个C++智能指针的例子,感觉不错,小改进了下,放出来。
智能指针的大意是:对普通的类(假设C)指针进行包装,内部维护一个引用计数。程序中只要使用智能指针包装类(假设SafeC)就行了。用的时候只用new C(), 然后把其给包装类进行构造,然后就随便用啦,不用担心C的析构问题了。
众所周知,C++中如果需要动态申请内存的话,就一定要释放。可是不是所有new出来的对象都能明确的知道该在哪里释放。释放的话,不知道在哪里释放才好,总不能某处正在使用着呢,就给delete了;不释放的话,就是传说中的内存泄漏。
所以,智能指针(好像也有叫安全指针的)的作用就显出来了。把一个申请来的对象指针,扔给智能指针去管理。智能指针会在对其所有引用都释放后,把内部管理的指针所指向的对象删除。使用起来的效果就像.Net和Java的引用一样。不过垃圾回收的机理应该和这个有些不同。
智能指针只使用值传递就可以,没有必要使用指针传递或引用传递,虽然效率高一点点。需要注意的是,智能指针就不要去new了,不然就失去其本来的意义了。
代码我改动了不少,还添加了测试代码。书上的代码只有很简单的非泛型的SafeC类。各种优缺点大家自己体会吧。(和Java或者是.Net对比一下,发现了这样写的优点了吧~)
另外说明一点:这个代码是没法在普通的C++环境下编译的,因为用的是C++.Net……用的.Net的控制台输出。大家把所有的输出代码删掉或改用C++的输出流就可以运行了(不要告诉我你看不出来哪个是.Net的东西啊……)。
另外:这个安全指针不是线程安全的,多线程中跨线程使用会出问题,需要添加线程锁。加锁一种可能的做法是:再维护一个锁对象的指针,在所有能接收到C新实例的指针的构造器中进行初始化,并与C的指针一同析构,在所有可能改变引用计数的地方进行线程同步,如构造器,赋值操作符,析构器。
代码:(自己写主函数)
template<class C> class SafeC { C* instance; int* count; private: void ShowCount() { Console::WriteLine("reference count in SafeC.constructor: " + *count); } public: SafeC(int i): instance(new C(i)), count(new int(1)) { ShowCount(); } SafeC(C* aInstance): instance(aInstance), count(new int(1)) { ShowCount(); } SafeC(const SafeC& other): instance(other.instance), count(other.count) { ++(*count); ShowCount(); } C* operator ->() { return instance; } C* operator =(const SafeC& other) { if(other.instance==instance) { return *this; } else { ~SafeC(); instance=other.instance; count=other.count; ++(*count); return *this; } } ~SafeC() { Console::WriteLine("in SafeC.destructor, before excute, count: "+*count); Console::WriteLine(" and the instance's id: "+instance->GetId()); if(--(*count) == 0) { Console::WriteLine(" and delete the pointer to instance !! instance's id: " + instance->GetId()); delete instance; delete count; } } };
相关测试代码:
class C1 { protected: int id; public: C1(int i):id(i) { Console::WriteLine("! in C1.C1, id: " + id); } virtual void Func() { Console::WriteLine("! in C1.f, id: " + id); } virtual int GetId() { return id; } virtual ~C1() { Console::WriteLine("! in C1.~C1, id: " + id); } }; class C2 : public C1 { public: C2(int i):C1(i) { } virtual void Func() { Console::WriteLine("! in C2.f, id: " + id); } virtual ~C2() { Console::WriteLine("! in C2.~C2, id: " + id); } }; void TestSafeC() { Console::WriteLine(">>>>> object in stack test:"); SafeC<C1> s1(new C1(1)); Console::WriteLine("s1"); SafeC<C1> s2(s1); Console::WriteLine("s2"); SafeC<C1>& rs3 = s2; Console::WriteLine("rs3"); SafeC<C1> s4 = s2; Console::WriteLine("invoke: s4->Func()"); s4->Func(); Console::WriteLine("<<<<< end stack test."); Console::WriteLine(">>>>> object in heap test:"); Console::WriteLine("ps5"); SafeC<C2>* ps5 = new SafeC<C2>(2); // not recommended. don't new SafeC, or it will be like a ordinary pointer. Console::WriteLine("rs6"); SafeC<C2>& rs6 = *new SafeC<C2>(3); // notice! no delete operation on this. this is dangerous. Console::WriteLine("s7"); SafeC<C2> s7 = *ps5; Console::WriteLine("delete ps5"); delete ps5; Console::WriteLine("<<<<< end heap test."); Console::WriteLine(">>>>> method return value test:"); C1* InnerFunc(); SafeC<C1> s8(InnerFunc()); // the most important point~ Console::WriteLine("<<<<< end method return value test."); } C1* InnerFunc() { return new C1(10); }
输出:
In Singleton's Constructor.
>>>>> object in stack test:
! in C1.C1, id: 1
reference count in SafeC.constructor: 1
s1
reference count in SafeC.constructor: 2
s2
rs3
reference count in SafeC.constructor: 3
invoke: s4->Func()
! in C1.f, id: 1
<<<<< end stack test.
>>>>> object in heap test:
ps5
! in C1.C1, id: 2
reference count in SafeC.constructor: 1
rs6
! in C1.C1, id: 3
reference count in SafeC.constructor: 1
s7
reference count in SafeC.constructor: 2
delete ps5
in SafeC.destructor, before excute, count: 2
and the instance's id: 2
<<<<< end heap test.
>>>>> method return value test:
! in C1.C1, id: 10
reference count in SafeC.constructor: 1
<<<<< end method return value test.
in SafeC.destructor, before excute, count: 1
and the instance's id: 10
and delete the pointer to instance !! instance's id: 10
! in C1.~C1, id: 10
in SafeC.destructor, before excute, count: 1
and the instance's id: 2
and delete the pointer to instance !! instance's id: 2
! in C2.~C2, id: 2
! in C1.~C1, id: 2
in SafeC.destructor, before excute, count: 3
and the instance's id: 1
in SafeC.destructor, before excute, count: 2
and the instance's id: 1
in SafeC.destructor, before excute, count: 1
and the instance's id: 1
and delete the pointer to instance !! instance's id: 1
! in C1.~C1, id: 1
相关文章推荐
- 怎样管理C++类中的指针成员 和 简单的c++智能指针使用的例子
- C++中智能指针的工作原理和简单实现
- C++中智能指针的工作原理和简单实现
- C++智能指针,指针容器原理及简单实现(auto_ptr,scoped_ptr,ptr_vector).
- C++智能指针简单剖析
- C++ 几种智能指针的简单实现
- 【转】C++智能指针简单剖析
- C++智能指针简单剖析
- C++智能指针及其简单实现
- C++智能指针的简单实现代码
- C++智能指针(一):智能指针的简单介绍
- C++ 引用计数技术及智能指针的简单实现
- C++智能指针简单剖析
- C++引用计数技术及智能指针的简单实现
- C++ 引用计数技术及智能指针的简单实现及改进
- [置顶]C++ 引用计数技术及智能指针的简单实现
- C++智能指针简单剖析
- 【转】C++ 引用计数技术及智能指针的简单实现
- C++中智能指针的工作原理和简单实现
- 一个简单的C++智能指针的实现