C++primer第十二章读书笔记---动态内存与智能指针
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++primer第十二章读书笔记---动态内存与智能指针相关的知识,希望对你有一定的参考价值。
目前为止我们使用过的静态内存,栈内存和内存池,静态内存用来保存局部static对象、类static成员,以及定义在任何函数之外的成员。栈内存用来保存定义在函数内部的非static成员,分配在静态 内存或栈内存中的对象由编译器自动创建或销毁,对于栈对象仅在其定义的程序块运行时才有效,static对象在程序运行之前分配,程序结束时销毁。除了静态内存和栈内存外,每个程序还拥有一个内存池(堆)在堆上分配动态对象,当动态对象不再使用时,我们必须显示的销毁它。 (一)、动态内存与智能指针 new在动态内存中为对象开辟空间,并返回指向该对象的指针;delete接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。 动态内存的使用很容易出现问题,有时候我们会忘记释放它,在这种情况下就会造成内存泄露,泄露的内存越堆积越多最终编译器无法为程序分配新的内存,系统崩溃。有时在尚有指针引用的内存的情况下我们就释放它,这种情况下会产生引用非法内存的指针。 说了这么多,让人感觉动态内存挺矫情的,不过矫情有矫情的治法,在这种情况下智能指针就能够很好地解决这种状况。智能指针行为类似常规指针,最最重要的区别就是它是一个负责任的指针,能够中自动释放所指向的对象。 (1)sharedptr--允许多个指针指向同一个对象 (2)scopedptr--守卫智能指针,简单粗暴 智能指针也是模板,因此当我们创建一个智能指针时必须提供额外的信息---智能指针指向的类型 在尖括号内给出类型,之后就是定义这种智能指针的名字: sharedptr<string> p1 //sharedptr,可以指向string sharedptr<list<int>> p2 //sharedptr,可以指向int的List链表 默认初始化的智能指针中保存着一个空指针,智能指针的使用方式与普通指针类似,解引用一个智能指针返回指向它的对象,如果在一个条件判断中使用智能指针,效果就是检测它是否为空。 (二)sharedptr自动销毁所管理的对象 当指向对象的最后一个sharedptr 被销毁时,sharedptr会自动销毁此对象,它通过析构函数完成销毁工作,析构函数一般用来释放对象所分配的资源。除此之外,sharedptr 还会自动释放相关联的内存。它是通过引用计数的方式来管理内存的, shardptr<T>P(q) p是sharedptr的拷贝,此操作会递增q中的引用计数,q中的指针必须转化为T* p=q p和q都是sharedptr,所保存的指针必须能够相互转化,此操作会递减p的引用计数,递增q的引用计数;若p的引用计数变为0,则将其管理的原来内存释放; 有关这两个指针的实现具体看后边的源代码哦 #include<iostream> using namespace std; template<typename T> //1 class Autoptr { public: //构造函数 Autoptr(T* ptr):_ptr(ptr) {} //析构函数 ~Autoptr() { if(_ptr) { cout<<"delete"<<_ptr<<endl; delete _ptr; _ptr=NULL; } } //拷贝构造函数 Autoptr(Autoptr<T> &ap):_ptr(ap._ptr) { ap._ptr=NULL; } //赋值运算符符重载 Autoptr<T>& operator=(Autoptr<T> &ap) { if(this!=&ap) { delete _ptr; _ptr=ap._ptr; ap._ptr=NULL; } return *this; } //->运算符重载 T* operator->() { return _ptr; } //*运算符重载 T&operator*() { return *_ptr; } private: T* _ptr; }; // template <typename T> class Scopedptr { public: // Scopedptr(T* ptr):_ptr(ptr) {} // ~Scopedptr() { if(_ptr) { cout<<"delete"<<_ptr<<endl; delete _ptr; } } //->运算符重载 T* operator->() { return _ptr; } //*运算符重载 T&operator*() { return *_ptr; } //防拷贝 //只声明不实现 // (1)声明为保护或私有成员防止函数在外边被篡改 // (2)防止调用默认的函数 protected: Scopedptr(Scopedptr<T> &sp); Scopedptr<T>&operator=(Scopedptr<T>& sp); protected: T *_ptr; }; template <typename T> class Shardptr { public: //构造函数 Shardptr(T *ptr) :_ptr(ptr) ,_pcount(new long(1)) { } //析构函数 ~Shardptr() { if(--(*_pcount)==0) { delete _ptr; delete _pcount; } } //拷贝构造函数 Shardptr(Shardptr<T>& sp) :_ptr(sp._ptr) ,_pcount(sp._pcount) { ++(*_pcount); } //赋值运算符重载 Shardptr<T>& operator=(const Shardptr<T>& sp) { //sp1=sp1 //sp1=sp2 //sp1=sp3 if(this_ptr!=sp._ptr) { if(--(*_pcount)==0) { delete _ptr; delete _pcount; } _ptr=sp._ptr; _pcount=sp._count; ++(*_pcount); } } // T& operator*() { return *_ptr; } // T* operator->() { return _ptr; } // long Usecount() { return *_pcount; } private: T*_ptr; long*_pcount; }; // template<typename> class ScopedArray { pubilc: ScopedArray(T* ptr):_ptr(ptr) {} ~ScopedArray() { if(_ptr) { delete [] _ptr; } } // T& oprator[](size_t index) { return _ptr[index]; } protected: ScopedArray(const ScopedArray<T>&sp); ScopedArray(const ScoopedArray<T>&sp); private: T * _ptr; }; void test1() { //int *p=new int(1); //Autoptr<int>ap(p); Autoptr<int>ap1(new int(1)); Autoptr<int>ap2(ap1); Autoptr<int>ap3(new int(2)); ap3=ap2; *ap3=10;//ap3.operator*(&ap3); /*Autoptr<int>ap4(new A); ap4->_a=10;*/ cout<<ap3.operator*()<<endl; } void test2() { //Scopedptr<int>sp1(new int(2)); } void TestShardptr() { Shardptr<int> sp1(new int(1)); Shardptr<int>sp2(sp1); *sp2=20; Shardptr<int>sp3(new int(3)); /*sp3=sp2;*/ cout<<"sp:"<<sp1.Usecount()<<endl; cout<<"sp2:"<<*sp2<<endl; } void TestScopedArray() { ScopedArray<A> sa(new A[10]); } int main() { TestShardptr(); system("pause"); return 0; }
以上是关于C++primer第十二章读书笔记---动态内存与智能指针的主要内容,如果未能解决你的问题,请参考以下文章