手机wap网站建设解决方案,网站备案找哪个部门,优秀建筑模型案例作品,做网站怎样和客户沟通智能指针
1.基础#xff1a;
1.1 概念 智能指针是用于自动管理动态分配内存的RAII#xff08;Resource Acquisition Is Initialization#xff09;对象。它们通过自动释放内存来防止内存泄漏#xff0c;是替代裸指针的安全工具。 1.2 解析 众所周知#xff0c;堆内存对象…智能指针
1.基础
1.1 概念 智能指针是用于自动管理动态分配内存的RAIIResource Acquisition Is Initialization对象。它们通过自动释放内存来防止内存泄漏是替代裸指针的安全工具。 1.2 解析 众所周知堆内存对象 需要 手动 使用 delete 销毁 如果 没有 使用 delete 销毁 就会 造成 内存 泄漏 。 所以C 在ISO9 8 标准 中 引入了 智能 指针 的 概念 并 在 I S O 1 1 中 趋于 完善 。 用智能指针可以让堆内存对象具有栈内存对象的特点原理是给需要手动回收的内内存对象套上一个栈内存的模板类对象的即可。 如下图智能指针类似把堆区指针对象放到新的指针类中进行管理这样就可以和栈区对象一样所处的{}结束就会自动释放内存不用手动delete。 2.分类 自动指针auto_ptr CISO98已被废除 唯一指针unique_ptr CIOS11 共享指针shared_ptr CIOS11 虚指针weak_ptr CIOS11 2.1 自动指针
(1)使用
#include iostream
#include memoryusing namespace std;class Animal{
private:string breed;string name;
public:Animal(string breed,string name):breed(breed),name(name){cout this-breed 构造函数 endl;}~Animal(){cout breed 析构函数 endl;}void print(){cout 物种 breed endl;cout 名字 name endl;}
};int main (){{Animal *a new Animal(狗,mike);auto_ptrAnimal ap1(a); //自动指针管理堆区指针对象aap1.get()-print(); //使用get函数调用管理的指针对象//ap1.release(); //直接放弃对已有指针对象a的管理不会释放堆区空间如果不delete对象a可能导致内存泄露//ap1.reset(); //放弃对已有指针对象a的管理同时释放堆区空间/**1. 放弃对原有指针的管理同时释放空间*2. 再创建新的堆区对象*3. ap1指针对新的堆区指针对象进行管理*/ap1.reset(new Animal(猫,lisa));ap1.get()-print(); //打印新管理的对象的成员变量cout 程序块运行结束 endl;}cout 程序运行结束 endl;return 0;
}(2)问题被废除原因 由于成员变量存在指针类型因此拷贝构造函数与赋值运算符重载的使用会出现问题与浅拷贝不同的是auto_ptr的复制语义会造成资源控制权转移的问题。 #include iostream
#include memoryusing namespace std;class Animal{
private:string breed;string name;
public:Animal(string breed,string name):breed(breed),name(name){cout this-breed 构造函数 endl;}~Animal(){cout breed 析构函数 endl;}void print(){cout 物种 breed endl;cout 名字 name endl;}
};int main (){{Animal *a new Animal(狗,mike);auto_ptrAnimal ap1(a); //自动指针管理堆区指针对象aauto_ptrAnimal ap2(ap1); //显示调用拷贝函数cout ap1.get() ap2.get() endl;auto_ptrAnimal ap3 ap2; //隐式调用拷贝函数cout ap1.get() ap2.get() ap3.get() endl;auto_ptrAnimal ap4;ap4 ap3; //调用的是重载的赋值运算符cout ap1.get() ap2.get() ap3.get() ap4.get() endl;cout 程序块运行结束 endl;}cout 程序运行结束 endl;return 0;
}2.2 唯一指针
(1)特点 1.和auto_ptr基本一致唯一的不同就是unique_ptr指针对资源对象有唯一控制权不能使用常规语法直接赋值和调用拷贝构造函数拷贝资源对象的控制权。 2.如果想让别的unique_ptr指针抢夺资源控制权就使用move(ap1)。 (2)使用
#include iostream
#include memoryusing namespace std;class Animal{
private:string breed;string name;
public:Animal(string breed,string name):breed(breed),name(name){cout this-breed 构造函数 endl;}~Animal(){cout breed 析构函数 endl;}void print(){cout 物种 breed endl;cout 名字 name endl;}
};int main (){{Animal *a new Animal(狗,mike);unique_ptrAnimal up1(a); //自动指针管理堆区指针对象aup1.get()-print();//unique_ptrAnimal up2(up1); //不使用move不能转移控制权下面两种方式一样unique_ptrAnimal up2(move(up1)); //显示调用拷贝函数cout up1.get() up2.get() endl;unique_ptrAnimal up3 move(up2); //隐式调用拷贝函数cout up1.get() up2.get() up3.get() endl;unique_ptrAnimal up4;up4 move(up3); //调用的是重载的赋值运算符cout up1.get() up2.get() up3.get() up4.get() endl;cout 程序块运行结束 endl;}cout 程序运行结束 endl;return 0;
}2.3 共享指针
(1)特点 1.对一个堆区对象进行管理解决了抢夺控制权转换的问题可以多个共享指针一起管理一个堆区对象。 2.新增一个引用计数对一起管理同一个对象的指针计数每多一个共享指针管理这个堆区对象引用计数加一。 3.当管理这个堆区空间的所有共享指针都被释放才会回收这个堆区对象。 4.shared_ptr有两种创建方式一种和之前的创建方式一样。第二种常用是其他智能指针没有的使用shared_ptr类型 sp1 make_shared类型(初始化内容)。 (2)使用
#include iostream
#include memoryusing namespace std;class Animal{
private:string breed;string name;
public:Animal(string breed,string name):breed(breed),name(name){cout this-breed 构造函数 endl;}~Animal(){cout breed 析构函数 endl;}void print(){cout 物种 breed endl;cout 名字 name endl;}
};int main (){shared_ptrAnimal sp3;{//shared_ptrAnimal sp1(new Animal(狗,mike)); //先创建堆区对象再让智能 指针引用管理堆区对象速度慢shared_ptrAnimal sp1 make_sharedAnimal(狗,mike); //直接创建智能指针并且引用对象一步到位sp1.get()-print();cout sp1.get() endl;cout 引用计数 sp1.use_count() endl;shared_ptrAnimal sp2 sp1; //隐式调用拷贝构造函数cout sp1.get() sp2.get() endl;cout 引用计数 sp1.use_count() endl;sp3 sp2; //赋值运算符重载cout sp1.get() sp2.get() sp3.get() endl;cout 引用计数 sp1.use_count() endl;cout 程序块运行结束 endl;}cout 引用计数 sp3.use_count() endl; //程序块结束只剩下ap3管理对象cout 程序运行结束 endl;return 0;
}2.4 虚指针
虚指针weak_ptr是用来观查共享指针所管理的资源像一个旁观者来记录观查的对象堆区对象是否被shared_ptr管理有几个share_ptr在管理。
(1)特点 1.虚指针weak_ptr是一个不控制资源对象管理的智能指针不会影响资源的引用计数主要的目的是协助share_ptr工作 2.通过weak_ptr的构造函数参数传入一个持有资源对象的share_ptr或者weak_ptr的指针 3.weak_ptr与资源呈弱相关性不能单独对资源进行控制不可以调用get()函数操作资源 4.weak_ptr可以调用.lock函数让shared_ptr指针获得一个持有资源的share_ptr在调用.lock函数前要先检测weak_ptr的引用计数是否大于零观察的资源是否还有shared_ptr指针还在管理如果没有对应的资源也不存在。 #include iostream
#include memoryusing namespace std;class Animal{
private:string breed;string name;
public:Animal(string breed,string name):breed(breed),name(name){cout this-breed 构造函数 endl;}~Animal(){cout breed 析构函数 endl;}void print(){cout 物种 breed endl;cout 名字 name endl;}
};int main (){weak_ptrAnimal wp2;shared_ptrAnimal sp3;{shared_ptrAnimal sp1 make_sharedAnimal(狗,mike); //直接创建智能指针并且引用对象一步到位sp1.get()-print(); //打印weak_ptrAnimal wp1(sp1); //使用虚函数wp1来观测共享指针对堆区对象引用次数不会增加引用计数cout 引用计数 sp1.use_count() endl;cout 引用计数 wp1.use_count() endl;shared_ptrAnimal sp2 sp1; //隐式调用拷贝构造函数//sp1.reset(); //删除当前共享指针如果还有其他共享指针管理就不释放所管理的资源wp2 sp2; //wp2也观测堆区对象cout 引用计数 sp1.use_count() wp2.use_count() endl;sp3 sp2;cout 程序块运行结束 endl;}//即使观测的共享指针被释放wp2依旧存在wp1被释放cout 引用计数 wp2.use_count() endl; //程序块结束虚函数观测管理资源对象的引用计数--0cout 程序运行结束 endl;return 0;
}3.手写一个共享指针Share_ptr类 构造函数拷贝构造函数赋值运算符get函数use_count函数reset函数析构函数 代码实现
#include iostream
#include memoryusing namespace std;template class T
class Shareptr{
private:T *res nullptr;int *count nullptr;
public:Shareptr(){}Shareptr(T *s):res(s),count(new int(1)){} //构造函数Shareptr(const Shareptr sp):res(sp.res),count(sp.count){ //拷贝构造函数(*count);}T* get()const{ //调用管理的资源return res;}int use_count()const{return *count;}void reset(){ //删除当前共享指针如果还有其他共享指针管理资源对象不删除资源对象if(count ! nullptr res ! nullptr){ //如果当前共享指针不是空(*count)--;if((*count) 0){delete res;delete count;}res nullptr;count nullptr;}}Shareptr operator (const Shareptr sp){ //赋值运算符重载if(sp ! this){reset();res sp.res;count sp.count;(*count);}return *this;}~Shareptr(){reset();}
};class Animal{
private:string breed;string name;
public:Animal(string breed,string name):breed(breed),name(name){cout this-breed 构造函数 endl;}~Animal(){cout breed 析构函数 endl;}void print(){cout 物种 breed endl;cout 名字 name endl;}
};int main (){ShareptrAnimal sp3;{//ShareptrAnimal sp1 make_sharedAnimal(金渐层,lisa);//ShareptrAnimal sp1 new Animal(金渐层,lisa); //隐式调用构造函数ShareptrAnimal sp1(new Animal(金渐层,lisa)); //显示调用构造函数sp1.get()-print();cout sp1.use_count() sp1.get() endl;ShareptrAnimal sp2 sp1; //调用拷贝构造函数cout sp1.use_count() sp1.get() endl;cout sp2.use_count() sp2.get() endl;sp3 sp1; //调用重载的赋值运算符cout sp1.use_count() sp1.get() endl;cout sp2.use_count() sp2.get() endl;cout sp3.use_count() sp3.get() endl;}cout 程序结束 endl;return 0;
}扩展shared_ptr 可能产生的内存泄露
问题描述
当两个或多个对象通过 shared_ptr 互相持有对方时会形成循环引用也叫“环状引用”。这样即使它们都不再被外部引用由于它们内部的 shared_ptr 还在互相引用引用计数永远不会归零导致内存无法释放产生内存泄漏。
错误示例
#include iostream
#include memory
using namespace std;class Car; // 前向声明class Person {
public:shared_ptrCar car;~Person() { cout Person destroyed endl; }
};class Car {
public:shared_ptrPerson owner;~Car() { cout Car destroyed endl; }
};int main() {auto p make_sharedPerson();auto c make_sharedCar();p-car c;c-owner p;// main 结束后Person 和 Car 都不会被销毁
}
运行后不会输出 A destroyed 和 B destroyed因为它们的引用计数始终大于0。
解决办法
用 weak_ptr 打破循环引用。
weak_ptr 是一种不增加引用计数的智能指针。通常在一方用 shared_ptr另一方用 weak_ptr。
修改后
#include iostream
#include memory
using namespace std;class Car; // 前向声明class Person {
public:shared_ptrCar car;~Person() { cout Person destroyed endl; }
};class Car {
public:weak_ptrPerson owner; // 用 weak_ptr~Car() { cout Car destroyed endl; }
};int main() {auto p make_sharedPerson();auto c make_sharedCar();p-car c;c-owner p; // 这里是 weak_ptr不增加引用计数// main 结束后Person 和 Car 都会被正确销毁
}
这样A 和 B 都会被正确释放输出 总结
循环引用会导致 shared_ptr 管理的对象无法释放造成内存泄漏。
用 weak_ptr 替代其中一方的 shared_ptr即可打破循环避免泄漏。