C++-智能指针

什么是智能指针

它将普通的指针封装为一个栈对象。当栈对象的生存周期结束后,会在析构函数中释放掉申请的内存
但是智能指针也会痴线内存泄漏问题

特点

智能指针会负责自动释放所指向的对象 主要是为了避免内存泄漏的问题

种类

共享指针shared_ptr

生命周期

C++-智能指针_第1张图片
shader_ptr在fun1中创建 传入了fun2 然后多线程调用指向了fun3 fun4 fun5 只有在所有fun执行完 也就是最后一个fun结束shader_ptr才会被销毁
C++-智能指针_第2张图片

用法

unique_ptr能用的 shader_ptr都能用 只是把unique_ptr换成shader_ptr
不同的是

    shared_ptr<int> p2  = p1; //use_count + 1
    shared_ptr<int> p3 = move(p1);//use-count不会+1 

函数传参

void foo(std::shader_ptr<int> p1)
{
}
void main()
{
	shader_ptr<int> p2 = std::make_<int>(7);
	foo(std::move(p2));//可以这样传值 use_count不会+1
	foo(p2);//也允许这样传参 use_count1
}

use_count()

用来查看资源的所有者个数
当计数为0时 这个指针就会被释放掉

unique()

返回是否是独占所有权( use_count 为 1)

swap()

交换两个 shared_ptr 对象(即交换所拥有的对象)

reset()

放弃内部对象的所有权或拥有对象的变更, 会引起原有对象的引用计数的减少

get()

返回内部对象(指针), 由于已经重载了()方法, 因此和直接使用对象是一样的.如 shared_ptr sp(new int(1)); sp 与 sp.get()是等价的

独享指针unique_ptr

特点

不允许拷贝 赋值
当unique_ptr被销毁,所指向的对象也被销毁

释放器(deleter)

当自身被销毁时 会使用自身关联的释放器释放所指向的对象
nique_ptr管理释放器是编译时绑定的

用法

    unique_ptr<string> p1(new string("hi,world")); // 必须采用直接初始化的形式初始化
    cout << *p1<<endl;//输出hi,world
    unique_ptr<string> p2(new string("hi")); 
    unique_ptr<int> p5(new int); //类似于普通指针的 int p5 = new int;//<>里面的是指针类型  	
    unique_ptr<int> p5 = new int;❌ 
    unique_ptr<int> p6 = std::make_unique<int>(7);//推荐方法!!()括号里可以填初始值
     unique_ptr<int> p8 = std::move(p6);//p6将不再拥有原来的对象7变为空指针 这个对象归p8拥有 一般传进函数里面作为形参就用这个例如fun(move(p6));
    auto p7 = std::make_unique<int>();//推荐方法!!
    unique_ptr<string> p2(p1); // ❌ 不支持拷贝
    unique_ptr<string> p3;
    p3 = p2; // ❌ 不支持赋值
	unique_ptr<string> p4(p1.release()); // 将p1置为空,并将p1原来的地址给p4 类似于初始化 但是由于是unique_ptr 只能有这一个指针指向这一个地址 不能多个unique_ptr指向一个地址
	
	p3.reset(p2.release());//reset会先释放p3原来指向的地址 再指向p2的地址 再将p2置为空
	cout<<*p4<<endl;//输出hi.world
	cout<<*p3<<endl;//输出hi
	cout<<*p2<<endl;//什么都不会输出
	

连续初始化

这样就会直接报错

    int* a = new int(5);
    unique_ptr<int> au1(a);
    unique_ptr<int> au(a);

release()(释放指针 并返回指针原来指向的对象)

pointer release() 一定要用个指针接住

unique_ptr<string> p4(p1.release()); // 将p1置为空,并将p1原来的地址给p4 类似于初始化 但是由于是unique_ptr 只能有这一个指针指向这一个地址 不能多个unique_ptr指向一个地址

reset()(释放指针 让该指针指向参数指针)

void reset(pointer p = pointer())

p3.reset(p2.release());/*reset会先释放p3原来指向的地址(就是把原来排
指向的那块地址直接释放掉) 再指向p2的地址 再将p2置为空*/
    int* a = new int(5);     
    int* b = new int(6);
    unique_ptr<int> au1(a);
    unique_ptr<int> au(b);
    au.reset(au1.release());
    cout << *b << endl;//垃圾值

swap(p,q)

p.swao(q);交换p和q的指针

get()

托管一个对象的指针或者空指针


unique_ptr<string> p1(new string("hello world"));
string *pstr = p1.get();
cout << *pstr << endl;

他与release()不同,它只是托管,get并是将pstr指向了p1指向的对象,但是并没有释放p1的内存,pstr并没有获取到这个智能指针的所有权,只是得到了它的对象。p1还是需要在某个时刻删除托管数据pstr

函数传参

void foo(std::unique_ptr<int> p1)
{
}
void main()
{
	unique_ptr<int> p2 = std::make_unique<int>(7);
	foo(std::move(p2));//只能这样传值 
}

如果我们这么写就会程序崩溃 因为外面的au已经失去了控制权

void fun(unique_ptr<int> au)
{
    cout << *au << endl;
}
int main()
{
    int* a = new int(5);
    unique_ptr<int> au(a);
    fun(move(au));
    cout << *au << endl;
    return 0;
}

要写成这样就可以

unique_ptr<int> fun(unique_ptr<int> au)
{
    cout << *au << endl;
    return move(au);
}
int main()
{
    int* a = new int(5);
    //au = a;//这样就不行 下面就行?
    au = fun(move(au));//但是不是不能赋值吗
    cout << *au << endl;
    return 0;
}

生命周期

C++-智能指针_第3张图片

弱指针weak_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的构造函数不会修改引用计数的值,从而不会对对象的内存进行管理,其类似一个普通指针,但不指向引用计数的共享内存,但是其可以检测到所管理的对象是否已经被释放,从而避免非法访问。

生命周期

C++-智能指针_第4张图片

void observe(std::weak_ptr<int> ew)
{
    if (shared_ptr<int> spt = ew.lock())//如果ew生命周期还存在则执行 不存在则执行else
    {
        cout << spt.use_count() << endl;
        cout << "entity still alive!" << endl;
    }
    else
    {
        cout << "entitywas expired :(" << endl;
    }
}
void main()
{
    cout << "entering main" << endl;
    weak_ptr<int> ew;
    {
        cout << "Entering ex4::scopel" << endl;
        auto e1 = make_shared<int>();
        cout << e1.use_count() << endl;
        ew = e1;
        cout << e1.use_count() << endl;
        observe(ew);
        cout << "Leaving ex4::scope1" << endl;//这里之后ew被销毁
    }
    observe(ew);//此时
    cout << "Leaving ex4" << endl;
}
  

特点

使用时一定要转换一个shader_ptr

用法

shader_ptr<int> p1 = std::make_shader<int>(7);
week_ptr<int> p2 = p1;//将week_ptr的p2变成shader_ptr p1
if(shader_ptr<int> p3 = p2.lock())//lock应该是判断生命周期是否结束 如果结束则返回空指针 如果没有结束则将p2给p3
{
	....
}

scoped_ptr(boost库的 boost库应该是被c++11取代了)

基本和auto_ptr一样
scoped_ptr和auto_ptr的根本区别在于所有权。auto_ptr特意被设计为指针的所有权是可以被转移的,可以在函数之间传递,同一时刻只能有一个auto_ptr管理指针。而scoped_ptr把拷贝构造函数和赋值函数都声明为私有的,拒绝了指针所有权的转让,只有scoped_ptr自己能够管理指针,其他任何人都无权访问被管理的指针,从而保证了指针的绝对安全。
就是可以

int *a = new int(10);
auto_ptr<int> aa(a);//就是auto_ptr指针aa获得了指针a的控制权
scoped_ptr<int> sa(aa);//这样就是sa从aa手上获得了控制权 此时aa不再控制a 由sa控制a
//auto_ptr aa1(sa);//不允许的
//auto_ptr aa1;aa1 = sa;//不允许的

智能指针头文件

# 仿造实现智能指针
template<class Ty>
class auto_ptr1
{
public:
    /*实现一下构造函数*/
    auto_ptr1(Ty* P = 0) :owns(P), ptr(P)//这个参数默认值为0 如果有值就会给类的两个成员变量进行赋值
    {
    }
    ~auto_ptr1()
    {
        if (owns)
        {
            delete ptr;
        }
    }
    /*这里就是实现指针解引用的功能 */
    Ty& operator*()const
    {
        return *ptr;
    }
    /*实现指针的->功能*/
    Ty* operator->()const
    {
        return ptr;
    }
private:
    bool owns;//就是用来判断是否有指向 如果没有指向就是false 
    Ty* ptr;
};
struct A
{
    A(int a)
    {
        val = a;
    }
    int val;
};
void main()
{
    A* a = new A(2);
    /*
    我们其实就是创建了一个类对象在栈区 
    然后这个对象在程序结束后自动销毁 
    然后我们这个对象会销毁他指向的那个在堆区指针指向的内存 就实现了智能
    */
    auto_ptr1<A>pa(a);//这就像我们找了一个管家管理这个指针
    cout << pa->val << endl;//2

    string* b = new string("sadf");
    auto_ptr1<string> zb(b);
    cout << *b << endl;//sadf
}

你可能感兴趣的:(C++,c++)