简单的网站设计图网站开发能怎么赚钱
- 作者: 五速梦信息网
- 时间: 2026年03月21日 10:46
当前位置: 首页 > news >正文
简单的网站设计图,网站开发能怎么赚钱,小红书关键词搜索量查询,开源手机网站模板智能指针 shared_ptrshared_ptr的基本用法使用shared_ptr要注意的问题 unique_ptr独占的智能指针weak_ptr弱引用的智能指针weak_ptr的基本用法weak_ptr返回this指针weak_ptr解决循环引用问题 weak_ptr使用注意事项 智能指针 C程序设计中使用堆内存是非常频繁的操作#xff0… 智能指针 shared_ptrshared_ptr的基本用法使用shared_ptr要注意的问题 unique_ptr独占的智能指针weak_ptr弱引用的智能指针weak_ptr的基本用法weak_ptr返回this指针weak_ptr解决循环引用问题 weak_ptr使用注意事项 智能指针 C程序设计中使用堆内存是非常频繁的操作堆内存的申请和释放都由程序员自己管理。程序员自己 管理堆内存可以提高了程序的效率但是整体来说堆内存的管理是麻烦的C11中引入了智能指针的 概念方便管理堆内存。使用普通指针容易造成堆内存泄露忘记释放二次释放程序发生异常 时内存泄露等问题等使用智能指针能更好的管理堆内存。 C里面的四个智能指针: auto_ptr,unique_ptr,shared_ptr, weak_ptr 其中后三个是C11支持 并且第一个已经被C11弃用。 shared_ptr 共享的智能指针 std::shared_ptr使用引用计数每一个shared_ptr的拷贝都指向相同的内存。再最后一个shared_ptr析 构的时候内存才会被释放。 shared_ptr共享被管理对象同一时刻可以有多个shared_ptr拥有对象的所有权当最后一个 shared_ptr对象销毁时被管理对象自动销毁。 简单来说shared_ptr实现包含了两部分 一个指向堆上创建的对象的裸指针:raw_ptr 一个指向内部隐藏的、共享的管理对象:share_count_object 第一部分没什么好说的第二部分是需要关注的重点. use_count当前这个堆上对象被多少对象引用了简单来说就是引用计数。 shared_ptr的基本用法 初始化 通过构造函数、std::shared_ptr辅助函数和reset方法来初始化shared_ptr代码如下 // 智能指针初始化std::shared_ptrint p1(new int(1));std::shared_ptrint p2 p1;std::shared_ptrint p3;p3.reset(new int(1));if(p3) {cout p3 is not null;} 我们应该优先使用make_shared来构造智能指针因为他更高效。 auto sp1 make_sharedint(100);//相当于shared_ptrint sp1(new int(100)); 不能将一个原始指针直接赋值给一个智能指针例如下面这种方法是错误的 std::shared_ptrint p new int(1); shared_ptr不能通过“直接将原始这种赋值”来初始化需要通过构造函数和辅助方法来初始化。 对于一个未初始化的智能指针可以通过reset方法来初始化当智能指针有值的时候调用reset会引起 引用计数减1。另外智能指针通过重载的bool类型操作符来判断是否为空。 #include iostream#include memoryusing namespace std;void test(shared_ptrint sp) {// sp在test里面的作用域cout test sp.use_count() sp.use_count() endl;}int main(){auto sp1 make_sharedint(100); // 优先使用make_shared来构造智能指针//相当于shared_ptrint sp2(new int(100));// std::shared_ptrint p new int(1); // 不能将一个原始指针直接赋值给一个智能指针std::shared_ptrint p1;p1.reset(new int(1)); // 有参数就是分配资源std::shared_ptrint p2 p1;// 引用计数此时应该是2cout p2.use_count() p2.use_count() endl; // 2cout p1.use_count() p1.use_count() endl; // 2p1.reset(); // 没有参数就是释放资源cout p1.reset()\n;// 引用计数此时应该是1cout p2.use_count() p2.use_count() endl; // 1cout p1.use_count() p1.use_count() endl; // 2if(!p1) { // p1是空的cout p1 is empty\n;}if(p2) { // p2非空cout p2 is not empty\n;}p2.reset();cout p2.reset()\n;cout p2.use_count() p2.use_count() endl;if(!p2) {cout p2 is empty\n;}shared_ptrint sp5(new int(100));test(sp5);cout sp5.use_count() sp5.use_count() endl;return 0;}/p2.use_count() 2p1.use_count() 2p1.reset()p2.use_count() 1p1.use_count() 0p1 is emptyp2 is not emptyp2.reset()p2.use_count() 0p2 is emptytest sp.use_count()2sp5.use_count()1/ 获取原始指针 当需要获取原始指针时可以通过get方法来返回原始指针代码如下所示 std::shared_ptrint ptr(new int(1));int *p ptr.get(); //万一不小心 delete p; 谨慎使用p.get()的返回值如果你不知道其危险性则永远不要调用get()函数。 p.get()的返回值就相当于一个裸指针的值不合适的使用这个值上述陷阱的所有错误都有可能发生 遵守以下几个约定 不要保存p.get()的返回值 无论是保存为裸指针还是shared_ptr都是错误的 保存为裸指针不知什么时候就会变成空悬指针保存为shared_ptr则产生了独立指针 不要delete p.get()的返回值 会导致对一块内存delete两次的错误 指定删除器 如果用shared_ptr管理非new对象或是没有析构函数的类时应当为其传递合适的删除器。 #include iostream#include memoryusing namespace std;void DeleteIntPtr(int *p) {cout call DeleteIntPtr endl;delete p;}int main(){std::shared_ptrint p(new int(1), DeleteIntPtr);std::shared_ptrint p2(new int(1), {cout call lambda1 delete p endl;delete p;});std::shared_ptrint p3(new int[10], {cout call lambda2 delete p endl;delete [] p; // 数组删除});return 0;}/call lambda2 delete pcall lambda1 delete pcall DeleteIntPtr/ 当p的引用计数为0时自动调用删除器DeleteIntPtr来释放对象的内存。删除器可以是一个lambda表达 式上面的写法可以改为 std::shared_ptrint p(new int(1), {cout call lambda delete p endl;delete p;}); 当我们用shared_ptr管理动态数组时需要指定删除器因为shared_ptr的默认删除器不支持数组对 象代码如下所示 std::shared_ptrint p3(new int[10], { delete [] p;}); 智能指针什么时候需要指定删除器 在需要 delete 以外的析构行为的时候用. 因为 shared_ptr 在引用计数为 0 后默认调用 delete ptr; 如果不满足需求就要提供定制的删除器. 一些场景: 资源不是 new 出来的(一般也意味着不能 delete), 比如可能是 malloc 出来的资源是被第三方库管理的 (第三方提供 资源获取 和 资源释放 接口, 那么要么写一个 wrapper 类要么就提供定制的 deleter)资源不是 RAII 的, 意味着析构函数不会把资源完全释放掉…也就是单纯 delete 还不够, 还得做额外的操作比如你的 end_connection 的例子. 虽然我觉得这个是 bad practice 使用shared_ptr要注意的问题 不要用一个原始指针初始化多个shared_ptr例如下面错误范例 int ptr new int; shared_ptrint p1(ptr); shared_ptrint p2(ptr); // 逻辑错误 不要在函数实参中创建shared_ptr对于下面的写法 function(shared_ptrint(new int), g()); //有缺陷 因为C的函数参数的计算顺序在不同的编译器不同的约定下可能是不一样的一般是从右到左但也 可能从左到右所以可能的过程是先new int然后调用g()如果恰好g()发生异常而shared_ptr还 没有创建 则int内存泄漏了正确的写法应该是先创建智能指针代码如下 shared_ptrint p(new int); function(p, g()); 形参和实参的区别和联系 形参变量只有在函数被调用时才会分配内存调用结束后立刻释放内存所以形参变量只有在函数内部有效不能在函数外部使用。实参可以是常量、变量、表达式、函数等无论实参是何种类型的数据在进行函数调用时它们都必须有确定的值以便把这些值传送给形参所以应该提前用赋值、输入等办法使实参获得确定值。实参和形参在数量上、类型上、顺序上必须严格一致否则会发生“类型不匹配”的错误。当然如果能够进行自动类型转换或者进行了强制类型转换那么实参类型也可以不同于形参类型。函数调用中发生的数据传递是单向的只能把实参的值传递给形参而不能把形参的值反向地传递给实参换句话说一旦完成数据的传递实参和形参就再也没有瓜葛了所以在函数调用过程中形参的值发生改变并不会影响实参。 请看下面的例子 #include stdio.h//计算从m加到n的值 int sum(int m, int n) {int i;for (i m1; i n; i) {m i;}return m; }int main() {int a, b, total;printf(Input two numbers: );scanf(%d %d, a, b);total sum(a, b);printf(a%d, b%d\n, a, b);printf(total%d\n, total);return 0; } / 运行结果 Input two numbers: 1 100 a1, b100 total5050 / 在这段代码中函数定义处的 m、n 是形参函数调用处的 a、b 是实参。通过 scanf() 可以读取用户输入的数据并赋值给 a、b在调用 sum() 函数时这份数据会传递给形参 m、n。 从运行情况看输入 a 值为 1即实参 a 的值为 1把这个值传递给函数 sum() 后形参 m 的初始值也为 1在函数执行过程中形参 m 的值变为 5050。函数运行结束后输出实参 a 的值仍为 1可见实参的值不会随形参的变化而变化。 通过shared_from_this()返回this指针。不要将this指针作为shared_ptr返回出来因为this指针 本质上是一个裸指针因此这样可能会导致重复析构看下面的例子。 //1-1-shared_from_this #include iostream #include memoryusing namespace std;class A { public:shared_ptrAGetSelf(){return shared_ptrA(this); // 不要这么做}~A(){cout Deconstruction A endl;} };int main() {shared_ptrA sp1(new A);shared_ptrA sp2 sp1-GetSelf();cout sp1.use_count() sp1.use_count() endl;cout sp2.use_count() sp2.use_count() endl;return 0; }/ sp1.use_count() 1 sp2.use_count() 1 Deconstruction A Deconstruction A / 在这个例子中由于用同一个指针this)构造了两个智能指针sp1和sp2而他们之间是没有任何关系 的在离开作用域之后this将会被构造的两个智能指针各自析构导致重复析构的错误。 正确返回this的shared_ptr的做法是让目标类通过std::enable_shared_from_this类然后使用基类的 成员函数shared_from_this()来返回this的shared_ptr如下所示。 //1-1-shared_from_this2 #include iostream #include memoryusing namespace std;class A: public std::enable_shared_from_thisA { public:shared_ptrAGetSelf(){return shared_from_this(); //}~A(){cout Deconstruction A endl;} };int main() {// auto spp make_sharedA();shared_ptrA sp1(new A);shared_ptrA sp2 sp1-GetSelf(); // ok// shared_ptrA sp2;// {// shared_ptrA sp1(new A);// sp2 sp1-GetSelf(); // ok// }cout sp1.use_count() sp1.use_count() endl;cout sp2.use_count() sp2.use_count() endl;return 0; } / sp1.use_count() 2 sp2.use_count() 2 Deconstruction A / 在weak_ptr章节我们继续讲解使用shared_from_this()的原因。 避免循环引用。循环引用会导致内存泄漏比如 #include iostream #include memory using namespace std;class A; class B;class A { public:std::shared_ptrB bptr;~A() {cout A is deleted endl;} };class B { public:std::shared_ptrA aptr;~B() {cout B is deleted endl; // 析构函数后才去释放成员变量} };int main() {std::shared_ptrA pa;{std::shared_ptrA ap(new A);std::shared_ptrB bp(new B);ap-bptr bp;bp-aptr ap;pa ap;// 是否可以手动释放呢 // ap.reset();ap-bptr.reset(); // 手动释放成员变量才行}cout main leave. pa.use_count() pa.use_count() endl; // 循环引用导致ap bp退出了作用域都没有析构return 0; }/ B is deleted main leave. pa.use_count()1 A is deleted */ 循环引用导致ap和bp的引用计数为2在离开作用域之后ap和bp的引用计数减为1并不回减为0导 致两个指针都不会被析构产生内存泄漏。 解决的办法是把A和B任何一个成员变量改为weak_ptr具体方法见weak_ptr章节。 什么是循环引用 循环引用circular reference是指在编程中两个或多个对象之间形成一个循环的引用关系导致这些对象之间的内存无法被正确释放从而引发内存泄漏。这种情况也被称为循环依赖或循环关联。 unique_ptr独占的智能指针 unique_ptr是一个独占型的智能指针它不允许其他的智能指针共享其内部的指针不允许通过赋值将 一个unique_ptr赋值给另一个unique_ptr。下面的错误示例。 unique_ptrT my_ptr(new T); unique_ptrT my_other_ptr my_ptr; // 报错不能复制 unique_ptr不允许复制但可以通过函数返回给其他的unique_ptr还可以通过std::move来转移到其 他的unique_ptr这样它本身就不再拥有原来指针的所有权了。例如 unique_ptrT my_ptr(new T); // 正确 unique_ptrT my_other_ptr std::move(my_ptr); // 正确 unique_ptrT ptr my_ptr; // 报错不能复制 std::make_shared是c11的一部分但std::make_unique不是。它是在c14里加入标准库的。 auto upw1(std::make_uniqueWidget()); // with make func std::unique_ptrWidget upw2(new Widget); // without make func 使用new的版本重复了被创建对象的键入但是make_unique函数则没有。重复类型违背了软件工程的 一个重要原则应该避免代码重复代码中的重复会引起编译次数增加导致目标代码膨胀。 除了unique_ptr的独占性 unique_ptr和shared_ptr还有一些区别比如 unique_ptr可以指向一个数组代码如下所示 std::unique_ptrint [] ptr(new int[10]); ptr[9] 9; std::shared_ptrint [] ptr2(new int[10]); // 这个是不合法的 unique_ptr指定删除器和shared_ptr有区别 std::shared_ptrint ptr3(new int(1), {delete p;}); // 正确 std::unique_ptrint ptr4(new int(1), {delete p;}); // 错误 unique_ptr需要确定删除器的类型所以不能像shared_ptr那样直接指定删除器可以这样写 std::unique_ptrint, void()(int) ptr5(new int(1), {delete p;}); //正确 关于shared_ptr和unique_ptr的使用场景是要根据实际应用需求来选择。如果希望只有一个智能指针管 理资源或者管理数组就用unique_ptr如果希望多个智能指针管理同一个资源就用shared_ptr。 #include iostream #include memory using namespace std;struct MyDelete {void operator()(int p){cout delete endl;delete p;} };int main() {auto upw1(std::make_uniqueint); // with make func make_unique需要设置c14std::unique_ptrint upw2(new int); // without make funcupw1[21] 1;std::unique_ptrint,MyDelete ptr2(new int(1)); // auto ptr(std::make_uniqueint, MyDelete(1));cout main finish! upw1[1] endl;return 0; }/ main finish! 0 delete */ weak_ptr弱引用的智能指针 share_ptr虽然已经很好用了但是有一点share_ptr智能指针还是有内存泄露的情况当两个对象相互 使用一个shared_ptr成员变量指向对方会造成循环引用使引用计数失效从而导致内存泄漏。 weak_ptr 是一种不控制对象生命周期的智能指针, 它指向一个 shared_ptr 管理的对象. 进行该对象的内 存管理的是那个强引用的shared_ptr weak_ptr只是提供了对管理对象的一个访问手段。weak_ptr 设 计的目的是为配合 shared_ptr 而引入的一种智能指针来协助 shared_ptr 工作, 它只可以从一个 shared_ptr 或另一个 weak_ptr 对象构造, 它的构造和析构不会引起引用记数的增加或减少。weak_ptr 是用来解决shared_ptr相互引用时的死锁问题如果说两个shared_ptr相互引用那么这两个指针的引 用计数永远不可能下降为0资源永远不会释放。它是对对象的一种弱引用不会增加对象的引用计数 和shared_ptr之间可以相互转化shared_ptr可以直接赋值给它它可以通过调用lock函数来获得 shared_ptr。 weak_ptr没有重载操作符*和-因为它不共享指针不能操作资源主要是为了通过shared_ptr获得 资源的监测权它的构造不会增加引用计数它的析构也不会减少引用计数纯粹只是作为一个旁观者 来监视shared_ptr中管理的资源是否存在。weak_ptr还可以返回this指针和解决循环引用的问题。 weak_ptr的基本用法 通过use_count()方法获取当前观察资源的引用计数如下所示 shared_ptrint sp(new int(10)); weak_ptrint wp(sp); cout wp.use_count() endl; //结果讲输出1 通过expired()方法判断所观察资源是否已经释放如下所示 shared_ptrint sp(new int(10)); weak_ptrint wp(sp); if(wp.expired())cout weak_ptr无效,资源已释放; elsecout weak_ptr有效; 通过lock方法获取监视的shared_ptr如下所示 std::weak_ptrint gw; void f() {if(gw.expired()) {cout gw无效,资源已释放;}else {auto spt gw.lock();cout gw有效, *spt spt endl;} }int main() {{auto sp atd::make_sharedint(42);gw sp;f();}f();return 0; } weak_ptr返回this指针 shared_ptr章节中提到不能直接将this指针返回shared_ptr需要通过派生 std::enable_shared_from_this类并通过其方法shared_from_this来返回指针原因是 std::enable_shared_from_this类中有一个weak_ptr这个weak_ptr用来观察this智能指针调用 shared_from_this()方法是会调用内部这个weak_ptr的lock()方法将所观察的shared_ptr返回再看 前面的范例 //1-1-shared_from_this2 #include iostream #include memoryusing namespace std;class A: public std::enable_shared_from_thisA { public:shared_ptrAGetSelf(){return shared_from_this(); }~A(){cout Deconstruction A endl;} };int main() {// auto spp make_sharedA();shared_ptrA sp1(new A);shared_ptrA sp2 sp1-GetSelf(); // ok// shared_ptrA sp2;// {// shared_ptrA sp1(new A);// sp2 sp1-GetSelf(); // ok// }cout sp1.use_count() sp1.use_count() endl;cout sp2.use_count() sp2.use_count() endl;return 0; } / sp1.use_count() 2 sp2.use_count() 2 Deconstruction A */ 在外面创建A对象的智能指针和通过对象返回this的智能指针都是安全的因为shared_from_this()是内 部的weak_ptr调用lock()方法之后返回的智能指针在离开作用域之后spy的引用计数减为0A对象会被析构不会出现A对象被析构两次的问题。 需要注意的是获取自身智能指针的函数尽量在shared_ptr的构造函数被调用之后才能使用因为 enable_shared_from_this内部的weak_ptr只有通过shared_ptr才能构造。 weak_ptr解决循环引用问题 在shared_ptr章节提到智能指针循环引用的问题因为智能指针的循环引用会导致内存泄漏可以通过 weak_ptr解决该问题只要将A或B的任意一个成员变量改为weak_ptr #include iostream #include memory using namespace std;class A; class B;class A { public:std::weak_ptrB bptr; // 修改为weak_ptrint val;A() {val new int(1);}~A() {cout A is deleted endl;delete val;} };class B { public:std::shared_ptrA aptr;~B() {cout B is deleted endl;} };//weak_ptr 是一种不控制对象生命周期的智能指针, void test() {std::shared_ptrA ap(new A);std::weak_ptrA wp1 ap;std::weak_ptrA wp2 ap;cout ap.use_count() ap.use_count() endl; }void test2() {std::weak_ptrA wp;{std::shared_ptrA ap(new A);wp ap;}cout wp.use_count() wp.use_count() , wp.expired(): wp.expired() endl;if(!wp.expired()) {// wp不能直接操作对象的成员、方法std::shared_ptrA ptr wp.lock(); // 需要先lock获取std::shared_ptrA(ptr-val) 20; } }int main() {test2(); // { // std::shared_ptrA ap(new A); // std::shared_ptrB bp(new B); // ap-bptr bp; // bp-aptr ap; // }cout main leave endl;return 0; } /* A is deleted wp.use_count()0, wp.expired():1 main leave / 这样在对B的成员赋值时即执行bp-aptrap;时由于aptr是weak_ptr它并不会增加引用计数所 以ap的引用计数仍然会是1在离开作用域之后ap的引用计数为减为0A指针会被析构析构后其内 部的bptr的引用计数会被减为1然后在离开作用域后bp引用计数又从1减为0B对象也被析构不会发 生内存泄漏。 weak_ptr使用注意事项 weak_ptr在使用前需要检查合法性。 weak_ptrint wp; {shared_ptrint sp(new int(1)); //sp.use_count()1wp sp; //wp不会改变引用计数所以sp.use_count()1shared_ptrint sp_ok wp.lock(); //wp没有重载-操作符。只能这样取所指向的对象 } shared_ptrint sp_null wp.lock(); //sp_null .use_count()0; 因为上述代码中sp和sp_ok离开了作用域其容纳的K对象已经被释放了。 得到了一个容纳NULL指针的sp_null对象。在使用wp前需要调用wp.expired()函数判断一下。 因为wp还仍旧存在虽然引用计数等于0仍有某处“全局”性的存储块保存着这个计数信息。直到最后 一个weak_ptr对象被析构这块“堆”存储块才能被回收。 如果shared_ptr sp_ok和weak_ptr wp;属于同一个作用域呢如下所示 weak_ptrint wp; shared_ptrint sp_ok; {shared_ptrint sp(new int(1)); //sp.use_count()1wp sp; //wp不会改变引用计数所以sp.use_count()1sp_ok wp.lock(); //wp没有重载-操作符。只能这样取所指向的对象 } if(wp.expired()) {cout shared_ptr is destroy endl; } else {cout shared_ptr no destroy endl; }/ shared_ptr no destroy */
相关文章
-
简单的网站管理系统做ps从哪个网站上下载图片大小
简单的网站管理系统做ps从哪个网站上下载图片大小
- 技术栈
- 2026年03月21日
-
简单的购物网站设计cj联盟wordpress
简单的购物网站设计cj联盟wordpress
- 技术栈
- 2026年03月21日
-
简单的方法搭建网站下载百度极速版免费安装
简单的方法搭建网站下载百度极速版免费安装
- 技术栈
- 2026年03月21日
-
简单的网站设计有一个网站是做釆购的是什么网
简单的网站设计有一个网站是做釆购的是什么网
- 技术栈
- 2026年03月21日
-
简单电商网站模板衡水电子网站建设
简单电商网站模板衡水电子网站建设
- 技术栈
- 2026年03月21日
-
简单电商网站模板网站弹幕代码
简单电商网站模板网站弹幕代码
- 技术栈
- 2026年03月21日
