C++智能指针

在使用普通指针的时候,需要在初始化的时候分配内存,用完之后再释放内存,如果没有及时释放内存,就会导致内存泄漏,久而久之内存满了之后程序崩溃;

智能指针就是会自动的进行内存的分配和释放,在C++中,使用智能指针需要引入头文件

#include <memory>

智能指针分为:unique_ptr,shared_ptr,weak_ptr

先看一下智能指针的简单实现

#include <iostream>
using namespace std;

class SmartPoint {
private:
    int* ptr;
public:
    explicit SmartPoint(int* p = NULL) { ptr = p; }    //构造函数初始化分配内存,使用explicit关键字防止构造函数隐式转换
    ~SmartPoint() { delete ptr; }    //析构时释放内存
    //重载操作符
    int& operator*() { return *ptr; }
};

int main() {
    SmartPoint ptr(new int());
    *ptr = 22;
    cout << *ptr << endl;    //22;
    return 0;
}

即使使用之后没有手动释放,智能指针在销毁时也会调用析构函数进行释放,加上泛型之后

#include <iostream>
using namespace std;

template<class T>
class SmartPoint {
private:
    T* ptr;
public:
    explicit SmartPoint(T* p = NULL) { ptr = p; }    //构造函数初始化分配内存,使用explicit关键字防止构造函数隐式转换
    ~SmartPoint() { delete ptr; }    //析构时释放内存
    //重载操作符
    T& operator*() { return *ptr; }
    T& operator->() { return ptr; }
};

int main() {
    SmartPoint<int> ptr(new int());
    *ptr = 22;
    cout << *ptr << endl;    //22;
    return 0;
}

正式的讲一讲智能指针

Unique_ptr

unique_ptr是独享所有权的智能指针,不能把共享资源,即不能同时两个unique_ptr指向同一块内存;可以通过move()进行所有权的转移,转移之后,被转移所有权的指针将不能再访问资源

#include <iostream>
#include <memory>
using namespace std;

class Person {
private:
    int age;
    boolean sex;
public:
    Person(int a, boolean s) {
        age = a;
        sex = s;
    }
    
    void printPerson() {
        cout << "age: " << age << ", sex: " << sex << endl;    
    }
};

int main() {
    unique_ptr<Person> p1(new Person(10, true));
    p1->printPerson();    //输出 age: 10, sex: 1;
    
    unique_ptr<Person> p2;
    //p2 = p1;  //无法共享,编译不通过
    
    //使用move()转移所有权
    p2 = move(p1);
    p2->printPerson();    //输出 age: 10, sex: 1;
    //p1->printPerson();    //p1已没有访问资源的权限,此语句运行时会抛出异常
    return 0;
}

Shared_ptr

shared_ptr是共享资源的指针,可以多个指针共享同一资源,采用了引用计数的机制和weak_count(weak_ptr)管理内存,当引用计数为0且weak_count为0即释放内存,使用use_count()可以查看当前引用计数

#include <iostream>
#include <memory>
using namespace std;

class Person {
private:
    int age;
    boolean sex;
public:
    Person(int a, boolean s) {
        age = a;
        sex = s;
    }
    
    void printPerson() {
        cout << "age: " << age << ", sex: " << sex << endl;    
    }
};

int main() {
    shared_ptr<Person> p1(new Person(10, 1));
    p1->printPerson();    //输出 age: 10, sex: 1;
    p1.use_count();    //1
    shared_ptr<Person> p2;
    p2 = p1;
    p2->printPerson();    //输出 age: 10, sex: 1;
    p1.use_count();    //2
    return 0;
}

Weak_ptr

shared_ptr可以共享资源,由于采用引用计数的问题,如果出现循环引用,则会导致引用计数出现问题,不能正确的释放内存,如下

#include <iostream>
#include <memory>
using namespace std;

class Woman;

class Man {
private:
    shared_ptr<Woman> woman;
public:
    Man() {
        cout << "Man Construction" << endl;
    }
    ~Man() {
        cout << "Man Deconstrcution" << endl;
    }
};

class Woman {
private:
    shared_ptr<Man> man;
public:
    Woman () {
        cout << "Woman Construction" << endl;
    }
    ~Woman () {
        cout << "Woman Deconstrcution" << endl;
    }
};

int main() {
    shared_ptr<Man> man(new Man());
    shared_ptr<Woman> woman(new Woman());
    
    man->woman = woman;
    woman->man = man;
    
    cout << man.use_count() << endl;     //2
    cout << woman.use_count() << endl;    //2

    return 0;
}

weak_ptr就是为了解决上述循环引用的问题而出现的,将shared_ptr被赋值给weak_ptr时,引用计数不会增加,weak_ptr是跟shared_ptr进行绑定的,weak_ptr可以用来跟踪shared_ptr对象,而不使引用计数改变,当引用计数为0时,shared_ptr释放资源,但不释放本身(内存),会等待weak_ptr的引用计数为0后,再释放自身。

也就是将上述代码中的一个shared_ptr改成weak_ptr即可

class Woman {
private:
    weak_ptr<Man> man;
public:
    Woman () {
        cout << "Woman Construction" << endl;
    }
    ~Woman () {
        cout << "Woman Deconstrcution" << endl;
    }
};

智能指针的创建

创建unique_ptr和shared_ptr时,有两种创建方式,一种是使用make_unique和make_shared,一种是上面的写法

make_unique

std::unique_ptr<Class> p1(new Class());
//make
auto p1(std::make_unique<Class>())

首先可以减少代码量,加快编译的速度,普通写法要写两次类名,编译器在编译时会进行两次类型推导,而使用make_unique,只写一次,即加快了编译速度;make_unique是不允许自定义析构器的

make_shared

从shared_ptr内存模型来看,一部分是资源区,一部分是用作管理区,使用普通创建方式,则会在堆上申请两次内存,第一次用作资源区,第二次用作管理区。而使用make_shared创建,则只会申请一次内存,一半用作资源区,一半用作管理区

虽然make_shared比较效率,但同样不能自定义析构器,而且shared_ptr对象会延迟释放,因为资源区和管理区是同一块内存

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值