C++-智能指针

目录

简单点,不要用指针,用类的实例解决问题
如果要用指针,不要用裸指针,优先考虑unique_ptr,其次是shared_ptr

unique_ptr

基本用法

#include <iostream>
#include <memory>

using std::cout;
using std::endl;


// 不能拷贝unique_ptr的规则有一个例外:我们可以拷贝或赋值一个将要被销毁的unique_ptr,将亡值

std::unique_ptr<int> func1(int a)
{
    return std::unique_ptr<int> (new int(a));
}

std::unique_ptr<int> func2(int a)
{
    std::unique_ptr<int> localVar{new int(a)};

    return localVar;
}


// 传unique_ptr参数可以使用引用避免所有权的转移,或者暂时的移交所有权
void func3(std::unique_ptr<int> &up)
{
    cout << "in func3, *up: " << *up << endl;

}


std::unique_ptr<int> func4(std::unique_ptr<int> up)
{
    // up相当于局部变量
    cout << "in func4, *up: " << *up << endl;
    return up;
}

void func()
{
    int *x {new int(100)};
    std::unique_ptr<int> up1, up2;

    // 不要与裸指针混用
    // 会使up1 up2指向同一个内存
    up1.reset(x);
    up2.reset(x);

}


int main()
{
    std::unique_ptr<int> up1{new int(100)};
    //std::unique_ptr<int> up1;  // *up1 出错,空智能指针也不能解引用
    cout << "*up1 : " << *up1 << endl;

    // 构造函数是explicit,不支持隐式转换,int * 不能给std::unique_ptr
    //std::unique_ptr<int> up2 = new int(10);

    // 不允许拷贝
    // std::unique_ptr<int> up3(up1);

    // unique_ptr拥有它所指向的对象,在某一时刻,只能有一个unique_ptr指向特定的对象
    // 当unique_ptr被销毁时,它所指向的对象也会被销毁

    // up1 = nullptr;  // 释放up1指向的对象,并将up1置为空

    std::unique_ptr<int> up2 {new int(10)};
    // 参数可以为 空、内置指针,先将up所指对象释放,然后重置up的值
    // up1.reset(up2);  // 不允许
    up1.reset(new int(20));
    cout << "after reset : *up1 " << *up1 << endl;

    // up放弃对它所指对象的控制权,并返回保存的指针,将up置为空
    // 但不会释放内存,所以要手动delete
    auto p_int = up1.release();
    delete p_int;

    // 传递unique_ptr
    up1 = func1(200);
    cout << "return unique_ptr : " << *up1 << endl;
    up1 = nullptr;

    up1 = func2(300);
    cout << "return unique_ptr : " << *up1 << endl;

    func3(up1);  // 传递引用,不拷贝,不涉及所有权转移
    // 暂时转移所有权,函数结束时返回拷贝,重新收回所有权
    up1 = func4(std::unique_ptr<int>(up1.release()));

    // 陷阱
    func();

    return 0;
}
#include <vector>
#include <typeinfo>
#include<memory>
#include <iostream>

class Person
{
public:
    ~Person()
    {
        std::cout << "delete" << std::endl;
    }

};


void func(std::unique_ptr<Person> uqi)
{
    std::cout << "in func" << std::endl;
}


int main(void)
{
    std::unique_ptr<Person> uqi {new Person};

    func(std::unique_ptr<Person>(uqi.release()));

    std::cout << "ok" << std::endl;


    return 0;
}

/*
in func
delete
ok
*/

std::move

#include <iostream>
#include <memory>

using std::cout;
using std::endl;

int main(int argc, char * argv[])
{
    // 智能指针独占指向的对象
    std::unique_ptr<double> pdata(new double{ 99.9 });
    *pdata = 100.0;

    cout << *pdata << endl;

    std::unique_ptr<double> pdata1;
    pdata1 = std::move(pdata);  // 不能直接赋值给其他智能指针,必须用move

    cout << *pdata1 << endl;
    cout << pdata << endl;

    return 0;
}

*unique_ptr

#include <iostream>
#include <memory>

using std::cout;
using std::endl;


int main()
{
    std::unique_ptr<int> up1{new int(100)};
    cout << "*up1 : " << *up1 << endl;

    std::unique_ptr<int> up2{new int(200)};
    cout << "*up2 : " << *up2 << endl;

    cout << "up1 ptr: " << up1.get() << endl;
    cout << "up2 ptr: " << up2.get() << endl;

     *up1 = *up2;  // up1指向空间的值更改为200
    cout << "*up1: " << *up1 << endl;
    cout << "up1 ptr: " << up1.get() << endl;
    cout << "up2 ptr: " << up2.get() << endl;


    return 0;
}

get方法

cppplusplus.com例子
// unique_ptr::get vs unique_ptr::release
#include <iostream>
#include <memory>

int main () {
                                           // foo   bar    p
                                           // ---   ---   ---
  std::unique_ptr<int> foo;                // null
  std::unique_ptr<int> bar;                // null  null
  int* p = nullptr;                        // null  null  null

  foo = std::unique_ptr<int>(new int(10)); // (10)  null  null
  bar = std::move(foo);                    // null  (10)  null
  p = bar.get();                           // null  (10)  (10)
  *p = 20;                                 // null  (20)  (20)
  p = nullptr;                             // null  (20)  null

  foo = std::unique_ptr<int>(new int(30)); // (30)  (20)  null
  p = foo.release();                       // null  (20)  (30)
  *p = 40;                                 // null  (20)  (40)

  std::cout << "foo: ";
  if (foo) std::cout << *foo << '\n'; else std::cout << "(null)\n";

  std::cout << "bar: ";
  if (bar) std::cout << *bar << '\n'; else std::cout << "(null)\n";

  std::cout << "p: ";
  if (p) std::cout << *p << '\n'; else std::cout << "(null)\n";
  std::cout << '\n';

  delete p;   // the program is now responsible of deleting the object pointed to by p
              // bar deletes its managed object automatically

  return 0;
}

shared_ptr

基本用法

#include <iostream>
#include <memory>

using std::cout;
using std::endl;


// 不要用p.get()的返回值为shared_ptr赋值
void func()
{
    std::shared_ptr<int> sp1(new int(10));

    // sp2保存了sp1的指针
    // 想法是 sp1和sp2的use_count都是2
    // 但是sp1和sp2的use_count都是1
    // sp1释放后,指向的空间被释放
    // 但是呢,sp2还没有被释放,可以指向的空间已经被释放了
    //   std::shared_ptr<int> sp2(sp1);
    std::shared_ptr<int> sp2(sp1.get());

    cout << "sp1 use_count: " << sp1.use_count() << endl;  // 1
    cout << "sp2 use_count: " << sp2.use_count() << endl;

}


void func1()
{
    int *x(new int(10));
    std::shared_ptr<int> sp1(x);
    std::shared_ptr<int> sp2(x);

    // sp1、sp2都指向x所指的内存,但它们是独立的
    // 那么这就很危险了,失去了共享指针的意义
    cout << "sp1 ptr: " << sp1.get() << endl;
    cout << "sp2 ptr: " << sp2.get() << endl;
    cout << "sp1 use_count: " << sp1.use_count() << endl;  // 1
    cout << "sp2 use_count: " << sp2.use_count() << endl;
}


int main()
{

    // 尽量用make_shared
    std::shared_ptr<int> sp(new int);
    cout << sp.use_count() << endl;  // 1

    sp = std::make_shared<int>(100);
    cout << sp.use_count() << endl;  // 1


    // explicit
    // error,不能进行隐式转换
    // std::shared_ptr<int> sp1 = new int(100);
    std::shared_ptr<int> sp1(new int(200));

    cout << "sp use_count: " << sp.use_count() << endl;  // 1
    cout << "sp1 use_count: " << sp1.use_count() << endl;

    sp = sp1;
    cout << "sp use_count: " << sp.use_count() << endl;  // 2
    cout << "sp1 use_count: " << sp1.use_count() << endl;

//    func();
    func1();
    return 0;
}

自定义删除器

基础

"shared_ptr"的传递删除器(deleter)方式比较简单, 只需要在参数中添加具体的删除器函数名, 即可; 注意是单参数函数;

#include <iostream>
#include <typeinfo>
#include <vector>

using std::cout;
using std::endl;

void deleter(int *ptr)
{
    delete ptr;

    ptr = nullptr;
    cout << "smart ptr delete the pointer" << endl;

}

int main(void)
{

    std::shared_ptr<int> sp1(new int(10), deleter);

    std::shared_ptr<int> sp2(new int, deleter);
    cout << typeid(sp2).name() << endl;

    // sp2用定义的deleter释放原来的内存
    // 改成了 make_shared<int>的智能指针,但是这个智能指针用的是默认删除器
    sp2 = std::make_shared<int>(15);

    // make_shared<int>返回的指针是默认删除器,而sp2定义的时候是自定义的删除器
    // 但是呢 两者可以赋值,说明两者是同一类型,这一点和unique_ptr不一样
    cout << typeid(sp2).name() << endl;

    cout << "*sp1 = " << *sp1 << endl;
    cout << "*sp2 = " << *sp2 << endl;


    return 0;
}


/*
class std::shared_ptr<int>
smart ptr delete the pointer  // 释放原来的空间
class std::shared_ptr<int>
*sp1 = 10
*sp2 = 15
smart ptr delete the pointer
*/

"unique_ptr"的删除器是函数模板(function template), 所以需要在模板类型传递删除器的类型(即函数指针(function pointer)), 再在参数中添加具体删除器;定义函数指针的类型, 包含三种方法(typedef, typedef decltype, using), 也可以直接传递decltype;

#include <iostream>
#include <typeinfo>
#include <vector>

using std::cout;
using std::endl;

void deleter(int *ptr)
{
    delete ptr;

    ptr = nullptr;
    cout << "smart ptr delete the pointer" << endl;

}

int main(void)
{
    // 函数指针的几种定义方法
    typedef void (*tp)(int *);
    typedef decltype(deleter)* dp;
    using up = void (*)(int*);

    // decltype(deleter) 是函数类型
    // 传递函数指针,decltype(deteter) * 才是函数类型的指针
    std::unique_ptr<int, decltype(deleter)*> upi(new int(20), deleter);
    std::unique_ptr<int, tp> upi1(new int(30), deleter);
    std::unique_ptr<int, dp> upi2(new int(35), deleter);
    std::unique_ptr<int, up> upi3(new int(40), deleter);
    std::unique_ptr<int> upi4(new int(0));  // 默认删除器

    cout << "upi typeid: " << typeid(upi).name() << endl;
    cout << "upi1 typeid: " << typeid(upi1).name() << endl;
    cout << "upi2 typeid: " << typeid(upi2).name() << endl;
    cout << "upi3 typeid: " << typeid(upi3).name() << endl;
    cout << "upi4 typeid: " << typeid(upi4).name() << endl;  // 不同的删除器的unique_ptr,类型不相同


    return 0;
}


/*
upi typeid: class std::unique_ptr<int,void (__cdecl*)(int * __ptr64)>
upi1 typeid: class std::unique_ptr<int,void (__cdecl*)(int * __ptr64)>
upi2 typeid: class std::unique_ptr<int,void (__cdecl*)(int * __ptr64)>
upi3 typeid: class std::unique_ptr<int,void (__cdecl*)(int * __ptr64)>
upi4 typeid: class std::unique_ptr<int,struct std::default_delete<int> >
smart ptr delete the pointer
smart ptr delete the pointer
smart ptr delete the pointer
smart ptr delete the pointer
*/

删除数组指针
如果定义了一个数组的智能指针,按道理需要用delete [] raw pointer,那么就必须指定删除器了

#include <iostream>
#include <typeinfo>
#include <vector>

using std::cout;
using std::endl;

void deleter(int *ptr)
{
    delete[] ptr;

    ptr = nullptr;
    cout << "smart ptr delete the pointer" << endl;

}

int main(void)
{
    // 自定义删除器
    // c++17也有数组写法了
    std::shared_ptr<int> spi(new int[10], deleter);


    // unique_ptr有这样的数组写法
    std::unique_ptr<int []> upi(new int[10]);

    return 0;
}
上一篇:LeetCode——unique-paths


下一篇:Laravel随笔 unique排除当前操作的数据