C++进阶语法——智能指针【C++深度学习部署(五)】

1、智能指针简介

1.1 原始指针(raw pointer)的⼀些问题
  • C++ 提供了内存管理的绝对自由度
    • 分配
    • 释放
    • 声明周期管理
  • ⼀些潜在严重问题
    • 未初始化的指针(wild pointer),也就是野指针,可指向内存的任何位置
    • 内存泄漏(memory leak),可能因为没有及时释放分配的内存空间
    • 悬空指针(dangling pointer):指针指向已经释放的对象
  • 所有权(ownership),引入智能指针
    • 谁拥有指针?
    • 何时可以删除指针?
1.2 智能指针(smart pointers)
  • 也是对象,是通过类模板实现的,
  • 只能指向堆上分配的内存
  • 用完后会自动删除
  • 遵循RAII(资源获取即初始化)原则,对资源的申请释放,是一种成对操作的封装
  • 几种C++ 智能指针:
    • Unique pointers (unique_ptr)
    • Shared pointers (shared_ptr)
    • Weak pointers (weak_ptr)
    • Auto pointers (auto_ptr) (已弃⽤)
  • 导入 #include <memory>
  • 在类模板(class templates)中定义
    • 对原始指针做了封装
    • 重载的操作符
      • 解引⽤(*)
      • 成员选择(->)
      • 不⽀持算数操作符(++, --等)

创建智能指针的具体实例如下,smart_pointer 可以换成上面提到的 unique_ptr,shared_ptr,weak_ptr,ptr 是指向 Type 类别的智能指针,当运行完 { } 里面的程序时,会自动调用析构函数,会帮助我们处理堆上分配的内存空间,

在这里插入图片描述

2、智能指针(smart pointers)——unique_ptr

  • unique_ptr<T> ptr_name
    • 指向heap堆上类型为 T 的对象
    • 唯⼀(unique),多个 unique_ptr 不可以指向同⼀个对象
    • 拥有指向对象的唯⼀所有权
    • 不可以复制或赋值,所以不能调用拷贝构造函数,但可以移动
    • 指针使⽤完毕,被指向的对象会⾃动释放销毁
2.1 unique_ptr 的声明

在这里插入图片描述

2.2 unique_ptr 的函数

在这里插入图片描述

2.3 自定义类型使用 unique_ptr

在这里插入图片描述

2.4 unique_ptr 不支持拷贝、赋值,但可以移动

std::move(p1):转移p1拥有的所有权,容器 vec 拥有堆上面对象的所有权,p1 会设置为空指针,

在这里插入图片描述

2.5 使用make_unique初始化(C++14标准)

make_unique 的作用也是在堆上创建内存空间,
auto 关键字是编译器根据 make_unique 的返回值自动帮我们判断数据类型,这里auto也是指向Account的unique_ptr ,

在这里插入图片描述

代码:
#include <iostream>
#include <vector>
#include <string>
#include <memory>

using namespace std;

class Account
{
private:
    string name {"account"};
    double balance {0.0};
public:
    Account(string name = "none", double balance = 0.0);
    ~Account();
    bool deposit(double amount);
    void printInfo() const;
    double getBalance();
};

Account::Account(string name, double balance)
    :name {name}, balance {balance}
{
    cout << "构造函数,name: " << name << endl;
}

Account::~Account()
{
    cout << "析构函数,name: " << name << endl;
}
bool Account::deposit(double amount)
{
    balance += amount;
    return true;
}

void Account::printInfo() const
{
    cout << "name: " << name << ", balance: " << balance << endl;
}
double Account::getBalance()
{
    return balance;
}

int main()
{
    
    // Account alice_account {"Alice", 1000.0}; // 构造函数和析构函数都会被调用

    // Account * bob_account = new Account {"Bob", 2000.0}; // 只有构造函数被调用
    // delete bob_account; // 析构函数被调用

    // unique_ptr<Account> p1 {new Account {"jams", 1000.0}}; // 构造函数和析构函数都会被调用

    // auto p2 = make_unique<Account>("mike", 2000.0); // 构造函数和析构函数都会被调用
    // unique_ptr<Account> p3;

    // // p3 = p2; // 报错,因为unique_ptr不允许拷贝,只能移动
    // p3 = move(p2); // p2 会被置为null,即空指针

    // if (! p2)
    //     cout << "p2 is null" << endl;

    // auto p4 = make_unique<Account>("Helen", 3000.0);
    // p4->deposit(1000.0);
    // p4->printInfo(); // 调用成员函数

    vector<unique_ptr<Account>> accounts;
    accounts.push_back( make_unique<Account>("alice",1000));
    accounts.push_back( make_unique<Account>("bob",500));
    accounts.push_back( make_unique<Account>("mike",1000));

    for (const auto &acc: accounts) 
        cout << acc->getBalance() << endl;

    return 0;
}

3、智能指针(smart pointers)——shared_ptr

  • shared_ptr<T> ptr_name
    • 指向heap堆上类型为 T 的对象
    • 不唯⼀,多个shared_ptr可以指向同⼀个对象
    • 被管理对象的所有权在多个shared_ptr中共享
    • 可以复制或赋值
    • 可以移动
    • 引⽤计数(reference count)为0,被指向的对象会⾃动释放销毁
3.1 shared_ptr的声明

当超出 { } 的作用域后,堆上的对象也会自动销毁,

在这里插入图片描述

3.2 shared_ptr的函数

use_count():返回引用计数的值,也就是当前堆上的对象被多少 shared_ptr 管理,
p1.reset() 并没有释放 p1 所指向的对象,因为 p2 还在指向这个对象,

在这里插入图片描述

3.3 自定义类型使用shared_ptr

在这里插入图片描述

3.4 vector和复制操作

在这里插入图片描述

3.5 使用make_shared初始化(C++11标注)

不再使用关键字 new,编译器也可以生成更高效的执行代码,所以推荐使用make_shared

在这里插入图片描述

代码:
#include <iostream>
#include <vector>
#include <string>
#include <memory>

using namespace std;

class Account
{
private:
    string name {"account"};
    double balance {0.0};
public:
    Account(string name = "none", double balance = 0.0);
    ~Account();
    void print() const;
};

Account::Account(string name, double balance)
    :name {name}, balance {balance}
{
    cout << "构造函数,name: " << name << endl;
}

Account::~Account()
{
    cout << "析构函数,name: " << name << endl;
}
void Account::print() const
{
    cout << "name: " << name << ", balance: " << balance << endl;
}

void test_func(shared_ptr<Account> p)
{
    cout << "p.use_count(): " << p.use_count() << endl; // 2
}

int main()
{
    // cout << "=====================" << endl;
    // shared_ptr<int> p1 {new int {100}};
    // cout << "p1.use_count(): " << p1.use_count() << endl; // 1

    // shared_ptr<int> p2 {p1}; // 共享所有权
    // cout << "p1.use_count(): " << p1.use_count() << endl; // 2

    // p1.reset(); // 释放所有权,但是不会销毁对象,因为p2还在使用
    // cout << "p1.use_count(): " << p1.use_count() << endl; // 0
    // cout << "p2.use_count(): " << p2.use_count() << endl; // 1


    // cout << "=====================" << endl;
    // shared_ptr<Account> p1 = make_shared<Account>("Alice", 1000.0);
    // test_func(p1);
    // cout << "p1.use_count(): " << p1.use_count() << endl; // 1

    // {
    //     shared_ptr<Account> p2 = p1;
    //     cout << "p2.use_count(): " << p2.use_count() << endl; // 3

    //     {
    //         shared_ptr<Account> p3 = p1;
    //         cout << "p3.use_count(): " << p3.use_count() << endl; // 4
            
    //         p1.reset();
    //     }
    //     cout << "p1.use_count(): " << p1.use_count() << endl; // 2
    //     cout << "p2.use_count(): " << p2.use_count() << endl; // 2
    // }
    // cout << "p1.use_count(): " << p1.use_count() << endl; // 1



    cout << "=====================" << endl;
    shared_ptr<Account> p1 = make_shared<Account>("Alice", 1000.0);
    shared_ptr<Account> p2 = make_shared<Account>("Bob", 2000.0);
    shared_ptr<Account> p3 = make_shared<Account>("Charlie", 3000.0);

    vector<shared_ptr<Account>> accounts;

    accounts.push_back(p1);
    accounts.push_back(p2);
    accounts.push_back(p3);

    for (const auto &p: accounts)
    {
        p->print();
        cout << "p.use_count(): " << p.use_count() << endl; // 1
    }
    return 0;
}

如果本文对你有帮助,请点赞收藏吧😊😊😊

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值