您的位置:首页 > 教育 > 锐评 > 打开浏览器自动弹出2345网址导航_中国品牌网官方网站_代写企业软文_网站建设纯免费官网

打开浏览器自动弹出2345网址导航_中国品牌网官方网站_代写企业软文_网站建设纯免费官网

2024/10/6 1:41:40 来源:https://blog.csdn.net/nongcha_ice/article/details/142705462  浏览:    关键词:打开浏览器自动弹出2345网址导航_中国品牌网官方网站_代写企业软文_网站建设纯免费官网
打开浏览器自动弹出2345网址导航_中国品牌网官方网站_代写企业软文_网站建设纯免费官网

文章目录

  • 智能指针
    • 为什么需要智能指针?
    • RAII
    • auto_ptr,管理权转移
    • unique_ptr,不允许拷贝
    • shared_ptr,引用计数
      • 循环引用
    • weak_ptr,不是RAII智能指针,专门解决循环引用问题

智能指针

为什么需要智能指针?

在C++中new一个对象以后,需要手动的释放这块空间,这样会触发很多情况,导致不能被释放。

int mian()
{pair<string,string>* p1 = new pair<string,string>;func();delete p1;return 0;
}

假如这里的func()函数抛出异常,那么delete不能够执行到位,会造成内存泄漏。

RAII

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:不需要显式地释放资源。采用这种方式,对象所需的资源在其生命期内始终保持有效。

第一个版本的智能指针

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
using namespace std;
template <class T>
class SmartPtr
{
public:SmartPtr(T* ptr):_ptr(ptr){}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;
};int main()
{SmartPtr<string> p1(new string("xxxxx"));SmartPtr<string> p2(new string("yyyyyy"));p1 = p2;return 0;
}

这个情况下,p1的指针指向p2的空间,造成p1的空间泄露,p2指向的空间不仅有p2指向,现在还有p1指向,会导致free两次。

auto_ptr,管理权转移

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<memory>
using namespace std;
class A
{
public: A(int a = 1):_a(a){cout << "A(int a = 1)" << endl;}~A(){cout << "~A()" << endl;}
//private:int _a;
};
int main()
{auto_ptr<A> p1(new A(1));auto_ptr<A> p2(new A(2));//auto_ptr 会将管理权转移,拷贝时,会把拷贝对象的资源管理权转移给被拷贝的对象//导致被拷贝对象悬空,访问就会出现问题auto_ptr<A> p3 = p1; //这里的p1就悬空了//崩溃p1->_a++;p3->_a++;return 0;
}

unique_ptr,不允许拷贝

template<class T>class unique_ptr{public:unique_ptr(T* ptr):_ptr(ptr){}//防止拷贝unique_ptr(unique_ptr<T>& ptr) = delete;unique_ptr<T> operator=(unique_ptr<T>& ptr) = delete;T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;};

shared_ptr,引用计数

#include <iostream>
using namespace std;template<class T>
class shared_ptr
{
public:shared_ptr(T* ptr): _ptr(ptr), _pcount(new int(1)){}~shared_ptr(){if (--(*_pcount) == 0){std::cout << "delete " << _ptr << std::endl;delete _ptr;delete _pcount;}}shared_ptr(const shared_ptr<T>& ptr): _ptr(ptr._ptr)//同一个类的实例可以互相访问私有变量, _pcount(ptr._pcount){(*_pcount)++;}shared_ptr<T>& operator=(const shared_ptr<T>& ptr){if (this == &ptr){return *this;}if (--(*_pcount) == 0){delete _ptr;delete _pcount;}_ptr = ptr._ptr;_pcount = ptr._pcount;++(*_pcount);return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}T* get(){return _ptr;}private:T* _ptr;int* _pcount;
};

循环引用

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<memory>
using namespace std;
class A
{
public: A(int a = 1):_a(a){cout << "A(int a = 1)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};
struct Node
{A _val;shared_ptr<Node> prev;shared_ptr<Node> next;
};
int main()
{shared_ptr<Node> sp1(new Node);shared_ptr<Node> sp2(new Node);sp1->next = sp2;sp2->prev = sp1;return 0;
}
  • Node 结构体包含了两个 sh ared_ptr<Node> 成员:prevnext,它们分别指向前一个和后一个节点。

  • shared_ptr 是一种智能指针,使用引用计数来管理对象的生命周期。当一个新的 shared_ptr 指向某个对象时,该对象的引用计数增加;当一个 shared_ptr 被销毁或指向其他对象时,引用计数减少。

  • sp1sp2 分别是两个 shared_ptr<Node> 对象,指向两个不同的 Node 实例。

  • 然后,sp1->next 被设置为 sp2sp2->prev 被设置为 sp1,这就导致了 sp1sp2 互相引用。

循环引用的产生

  1. sp1 引用 sp2

    • sp1->next = sp2 执行后,sp1 中的 next 指向了 sp2,这意味着 sp2 的引用计数增加了 1。
  2. sp2 引用 sp1

    • sp2->prev = sp1 执行后,sp2 中的 prev 指向了 sp1,这意味着 sp1 的引用计数也增加了 1。

由于 sp1sp2 互相引用对方,形成了一个循环引用。

循环引用的后果

main 函数结束时,sp1sp2 都应该被销毁,然而,由于它们互相引用,两个 shared_ptr 的引用计数都不会降到 0,因此内存不会被释放。

  • sp1 持有一个指向 sp2shared_ptr,这使得 sp2 的引用计数永远不会降到 0。
  • 同样,sp2 持有一个指向 sp1shared_ptr,使得 sp1 的引用计数也永远不会降到 0。

这种情况下,即使 sp1sp2 超出了作用域并且 main 函数结束了,它们所指向的 Node 对象依然无法被销毁,导致内存泄漏。

weak_ptr,不是RAII智能指针,专门解决循环引用问题

原理:不增加引用计数,不参与资源的释放管理,可以访问资源。

template<class T>class weak_ptr{public:weak_ptr(T* ptr = nullptr):_ptr(ptr){}weak_ptr(const shared_ptr<T>& sp):_ptr(sp.get()){}weak_ptr<T>& operator=(const shared_ptr<T>& sp){_ptr = sp.get();return *this;}T& operator*(){return *_ptr;}T* operator->(){return _ptr;}private:T* _ptr;};

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com