美文网首页
018-智能指针

018-智能指针

作者: 一亩三分甜 | 来源:发表于2021-10-08 11:38 被阅读0次

《C++文章汇总》
上一篇介绍了《017-异常》,本文介绍智能指针。

智能指针

◼ 传统指针存在的问题

需要手动管理内存
容易发生内存泄露(忘记释放、出现异常等)
释放之后产生野指针
◼ 智能指针就是为了解决传统指针存在的问题
auto_ptr:属于C++98标准,在C++11中已经不推荐使用(有缺陷,比如不能用于数组)
shared_ptr:属于C++11标准
unique_ptr:属于C++11标准

1.auto_ptr,无须delete,自动调用析构函数,person对象的生命周期跟随智能指针,智能指针处于栈空间,临时变量,在函数结束时销毁,一旦没有智能指针指向person对象,则person对象也销毁

void test(){
//    Person *p = new Person();
    //可以理解为:只能指针p指向了堆空间的person对象
    auto_ptr<Person> p(new Person());
}

class Person {
    int m_age;
public:
    Person(){
        cout << "Person()" << endl;
    }
    Person(int age):m_age(age){
        cout << "Person() m_age:"<< age << endl;
    }
    ~Person(){
        cout << "~Person()" << endl;
    }
    void run(){
        cout << "run------" << m_age << endl;
    }
};
void test(){
//    Person *p = new Person();
    //可以理解为:智能指针p指向了堆空间的person对象
    auto_ptr<Person> p(new Person(20));
    p->run();
}
//输出
Person() m_age:20
run------20
~Person()

作用域

cout << 1 << endl;
{
    auto_ptr<Person> p(new Person(20));
    p->run();
}
cout << 2 << endl;
//输出
1
Person() m_age:20
run------20
~Person()
2

智能指针不要去指向栈空间的对象,否则易导致两次析构,智能指针设计是用来指向堆空间的对象的,如下两次析构,第一次是作用域内person指向栈空间的对象析构,第二次是智能指针指向的person对象的栈空间析构

cout << 1 << endl;
{
    Person person(10);
    auto_ptr<Person> p(&person);
    p->run();
}
cout << 2 << endl;
//输出
1
Person() m_age:10
run------10
~Person()
042-智能指针(16903,0x1000e2dc0) malloc: *** error for object 0x7ffeefbff4b8: pointer being freed was not allocated
042-智能指针(16903,0x1000e2dc0) malloc: *** set a breakpoint in malloc_error_break to debug

2.自定义智能指针

template <typename T>
class SmartPointer{
private:
    T *m_obj;
public:
    SmartPointer(T *obj):m_obj(obj){
    }
    ~SmartPointer(){
        if (m_obj == nullptr) return;
        delete m_obj;
    }
};
int main(){
    {
        SmartPointer<Person> p(new Person(20));
    }
    getchar();
    return 0;
}
//输出
1
Person() m_age:20
~Person()
2

此时如何通过智能指针p调用person对象中的方法呢?p->run();直接调用会报错。
通过运算符重载,重载运算符的功能,用指针运算符->时返回Person *的指针m_obj,即p->run()相当于m_obj->run();

template <typename T>
class SmartPointer{
private:
    T *m_obj;
public:
    SmartPointer(T *obj):m_obj(obj){
    }
    ~SmartPointer(){
        if (m_obj == nullptr) return;
        delete m_obj;
    }
    T *operator->(){
        return m_obj;
    }
};
int main(){
    cout << 1 << endl;
    {
        SmartPointer<Person> p(new Person(20));
        p->run();
    }
    cout << 2 << endl;
    getchar();
    return 0;
}
//输出
1
Person() m_age:20
run------20
~Person()
2

智能指针是对传统指针的再次封装,构造时传入对象,里面有一个传统指针m_obj指向传入的对象内存地址,析构时,智能指针p释放掉,传统指针指向的对象内存也释放delete m_obj
调用方法时,通过运算符重载,返回指向对象内存地址的传统指针
智能指针是一个对象,重载了指针运算符后返回一个指针

3.auto_ptr缺陷,不支持数组,不能指向数组

传入数组申请了创建了10个对象,但仅仅只析构了一次

template <typename T>
class SmartPointer{
private:
    T *m_obj;
public:
    SmartPointer(T *obj):m_obj(obj){
    }
    ~SmartPointer(){
        if (m_obj == nullptr) return;
        delete m_obj;
    }
    T *operator->(){
        return m_obj;
    }
};
int main(){
    //传入数组,创建10个person对象,但仅仅只会析构一次
    {
        SmartPointer<Person> p(new Person[10]);
        p->run();
    }
    getchar();
    return 0;
}
//输出
Person()
Person()
Person()
Person()
Person()
Person()
Person()
Person()
Person()
Person()
run------0
~Person()
044-智能指针auto_ptr缺陷(92475,0x1000e2dc0) malloc: *** error for object 0x10048fbb8: pointer being freed was not allocated
044-智能指针auto_ptr缺陷(92475,0x1000e2dc0) malloc: *** set a breakpoint in malloc_error_break to debug

4.shared_ptr

◼ shared_ptr的设计理念 多个shared_ptr可以指向同一个对象,当最后一个shared_ptr在作用域范围内结束时,对象才会被自动释放

cout << 1 << endl;
{
    shared_ptr<Person> p4;
    {
        shared_ptr<Person> p1(new Person(20));
        shared_ptr<Person> p2 = p1;
        shared_ptr<Person> p3 = p2;
        p4 = p3;
    }
    cout << 2 << endl;
}
cout << 3 << endl;
//输出
1
Person() m_age:20
2
~Person()
3

◼ 可以通过一个已存在的智能指针初始化一个新的智能指针


图片.png

I.指向单个对象

cout << 1 << endl;
{
    shared_ptr<Person> p(new Person(20));
    p->run();
}
//输出
1
Person() m_age:20
run------20
~Person()
2

II.指向数组

cout << 1 << endl;
{
    shared_ptr<Person> p(new Person[5],[](Person *p){
        delete[] p;
    });
}
cout << 2 << endl;
//输出
1
Person()
Person()
Person()
Person()
Person()
~Person()
~Person()
~Person()
~Person()
~Person()
2

◼一个shared_ptr会对一个对象产生强引用(strong reference)
◼ 每个对象都有个与之对应的强引用计数,记录着当前对象被多少个shared_ptr强引用着
可以通过shared_ptr的use_count函数获得强引用计数
◼ 当有一个新的shared_ptr指向对象时,对象的强引用计数就会+1
◼ 当有一个shared_ptr销毁时(比如作用域结束),对象的强引用计数就会-1
◼ 当一个对象的强引用计数为0时(没有任何shared_ptr指向对象时),对象就会自动销毁(析构)

III.use_count()获取对象强引用数量,即一个对象有多少个智能指针指向

{
    shared_ptr<Person> p4;
    {
        shared_ptr<Person> p1(new Person(20));
        cout << p1.use_count() << endl;
        shared_ptr<Person> p2 = p1;
        cout << p2.use_count() << endl;
        shared_ptr<Person> p3 = p2;
        cout << p3.use_count() << endl;
        p4 = p3;
        cout << p4.use_count() << endl;
    }
}
//输出
Person() m_age:20
1
2
3
4
~Person()

指向对象的智能指针销毁一个,use_count就会减一

{
    shared_ptr<Person> p4;
    {
        shared_ptr<Person> p1(new Person(10));
        cout << p1.use_count() << endl;//1
        shared_ptr<Person> p3;
        {
            shared_ptr<Person> p2 = p1;
            cout << p2.use_count() << endl;//2
            
            p3 = p2;//3
        }//2
        cout << p3.use_count() << endl;
        p4 = p3;//3
        cout << p4.use_count() << endl;
    }
    cout << p4.use_count() << endl;//1
}
//输出
Person() m_age:10
1
2
2
3
1
~Person()

IV.shared_ptr易出现的问题,两次析构,程序崩溃

Person *p = new Person();
{
    shared_ptr<Person> p1(p);
}//析构~Person()
{
    shared_ptr<Person> p2(p);
}//析构~Person()
//输出
Person()
~Person()
~Person()
045-shared_ptr易出现的问题(79269,0x1000e6dc0) malloc: *** error for object 0x100487ff0: pointer being freed was not allocated
045-shared_ptr易出现的问题(79269,0x1000e6dc0) malloc: *** set a breakpoint in malloc_error_break to debug

V.shared_ptr循环引用的问题:相互持有,始终无法销毁

class Car;
class Person {
public:
    shared_ptr<Car> m_car;
    Person(){
        cout << "Person()" << endl;
    }
    ~Person(){
        cout << "~Person()" << endl;
    }
};
class Car{
public:
    shared_ptr<Person> m_person;
    Car(){
        cout << "Car()" << endl;
    }
    ~Car(){
        cout << "~Car()" << endl;
    }
};
int main(){
    
    {
        shared_ptr<Person> person(new Person());
        shared_ptr<Car> car(new Car());
        person->m_car = car;
        car->m_person = person;
    }
    getchar();
    return 0;
}
//输出
Person()
Car()
图片.png

5.weak_ptr

◼ weak_ptr会对一个对象产生弱引用
◼ weak_ptr可以指向对象解决shared_ptr的循环引用问题

class Car;
class Person {
public:
    weak_ptr<Car> m_car;
    Person(){
        cout << "Person()" << endl;
    }
    ~Person(){
        cout << "~Person()" << endl;
    }
};
class Car{
public:
    shared_ptr<Person> m_person;
    Car(){
        cout << "Car()" << endl;
    }
    ~Car(){
        cout << "~Car()" << endl;
    }
};
int main(){
    
    {
        shared_ptr<Person> person(new Person());
        shared_ptr<Car> car(new Car());
        person->m_car = car;
        car->m_person = person;
    }
    getchar();
    return 0;
}
//输出
Person()
Car()
~Car()
~Person()
图片.png

若是使用普通指针,自己会写delete,不存在循环引用的问题,循环引用只是针对智能指针引起的

6.unique_ptr

◼ unique_ptr也会对一个对象产生强引用,它可以确保同一时间只有1个指针指向对象
◼ 当unique_ptr销毁时(作用域结束时),其指向的对象也就自动销毁了
◼ 可以使用std::move函数转移unique_ptr的所有权

class Person {
public:
    int m_age;
    Person(){
        cout << "Person()" << endl;
    }
    Person(int age):m_age(age){
        cout << "Person(int age )"<< m_age << endl;
    }
    ~Person(){
        cout << "~Person()" << endl;
    }
};
int main(){
    {
        unique_ptr<Person> person(new Person(20));
    }
    getchar();
    return 0;
}
//输出
Person(int age )20
~Person()

不能多个unique_ptr指向同一个对象,会报错

int main(){
    {
        unique_ptr<Person> person(new Person(20));
        unique_ptr<Person> p1(person);
    }
    getchar();
    return 0;
}
//编译报错
Call to implicitly-deleted copy constructor of 'unique_ptr<Person>'

std::move转移智能指针的指向,p1指向person对象,后面转移给p0指向person对象

unique_ptr<Person> p0;
{
    //p1强引用着Person对象
    unique_ptr<Person> p1(new Person(20));
    //转移之后,p0强引用着Person对象
    p0 = std::move(p1);
}

相关文章

  • 018-智能指针

    《C++文章汇总》[https://www.jianshu.com/p/bbd842438420]上一篇介绍了《0...

  • 目录

    智能指针(1) 智能指针(2) 智能指针(3) 智能指针之使用 容器 - vector(1) 容器 - vecto...

  • 智能指针到Android引用计数

    智能指针 LightRefBase RefBaseStrongPointerWeakPointer 智能指针 这是...

  • C++面试重点再梳理

    智能指针 请讲一下智能指针原理,并实现一个简单的智能指针 智能指针其实不是一个指针。它是一个用来帮助我们管理指针的...

  • C++研发工程师笔试题/面试题(1-10)

    1. (1) 简述智能指针的原理;(2)c++中常用的智能指针有哪些?(3)实现一个简单的智能指针。 简述智能指针...

  • 第十六章 string类和标准模板库(2)智能指针模板类

    (二)智能指针模板类 智能指针是行为类似指针的类对象,但这种对象还有其他便于管理内存的功能。 1.使用智能指针 (...

  • Rust for cpp devs - 智能指针

    与 cpp 类似,Rust 也有智能指针。Rust 中的智能指针与引用最大的不同是,智能指针 own 内存,而引用...

  • C++ 引用计数技术及智能指针的简单实现

    1.智能指针是什么 简单来说,智能指针是一个类,它对普通指针进行封装,使智能指针类对象具有普通指针类型一样的操作。...

  • 智能指针

    1. 什么是智能指针? 智能指针是行为类似于指针的类对象,但这种对象还有其他功能。 2. 为什么设计智能指针? 引...

  • chrome中智能指针使用

    chrom中智能指针的概述和作用 chrome中智能指针的用法和总结 包含如下四种智能指针:scoped_ptr ...

网友评论

      本文标题:018-智能指针

      本文链接:https://www.haomeiwen.com/subject/cajanltx.html