C++11中的智能指针

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数C初学者入门训练题解CC的使用文章「初学」C++linux

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

RAII

智能指针

auto_ptr

auto_ptr的简单实现

unique_ptr

unique_ptr的实现

shared_ptr

shared_ptr的实现

weak_ptr

weak_ptr的实现


RAII

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在

对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。

这种做法有两大好处:

不需要显式地释放资源。

采用这种方式,对象所需的资源在其生命期内始终保持有效。

事例

template<class T>
class SmartPtr
{
public:
    SmartPtr(T* ptr):_ptr(ptr)
    {
      
    }
    ~SmartPtr()
    {
        delete[] _ptr;
        cout<<"~ delete[] _ptr";
    }
    T* _ptr;
};

double Division(int len,int time)
{
    if(time==0)
    {
        throw "除0错误";
    }
    else
    {
        return (double)len/time;
    }
}
void func()
{
    int* p1=new int[]{1,2,3};
    SmartPtr<int> sp(p1);//这样将p1托管智能指针sp,当sp声明周期结束时,p1动态申请的资源就会自动释放,以前我们动态开辟内存后,我们会忘记释放内存,而现在只需要将资源托管给智能指针,就可以完成资源的自动释放
    int len,time;
    cin>>len>>time;
    cout<<Division(len, time)<<endl;
    delete p1;
}
int main()
{
    try
    {
        func();
    }
    catch(const char* str)
    {
        cout<<str<<endl;
    }
    catch(...)
    {
        cout<<"未知异常"<<endl;
    }
    return 0;
}

严格来说我们上面实现的SmartPtr不算是智能指针,还缺少指针该有的操作,例如解引用

智能指针

智能指针就是RAII的思想的具体实例,智能指针是一种用于管理动态分配内存的 C++ 类模板,它们提供了自动内存管理的功能,以减少内存泄漏和野指针的问题。

auto_ptr

std::auto_ptr 是 C++98 标准库中提供的一种智能指针,用于管理动态分配的内存资源。它是 C++ 标准库中最早引入的智能指针之一,但在 C++11 标准中已经被标记为废弃(deprecated)并在 C++17 中被移除。

std::auto_ptr 与其他智能指针不同,它采用了所有权转移(ownership transfer)的方式,即在将资源(比如动态分配的内存)赋值给另一个 std::auto_ptr 后,原来的 std::auto_ptr 将不再拥有该资源。这意味着只能通过拷贝构造函数或移动构造函数来转移所有权,而不能通过赋值操作符(=)来转移所有权。

由于 std::auto_ptr 存在许多问题,比如无法与标准库容器一起使用、潜在的内存泄漏问题等,因此它已经被更安全和更灵活的智能指针 std::unique_ptr 所取代。

以下是一个简单的示例,演示了 std::auto_ptr 的使用方式:

#include <iostream>
#include <memory>

int main() {
    std::auto_ptr<int> ptr1(new int(42));
    std::cout << "ptr1: " << *ptr1 << std::endl;

    std::auto_ptr<int> ptr2;
    ptr2 = ptr1; // 所有权转移
    // 此时,ptr1 不再拥有资源

    std::cout << "ptr2: " << *ptr2 << std::endl;

    // 尝试访问 ptr1,会导致未定义行为,野指针行为
    // std::cout << "ptr1: " << *ptr1 << std::endl;

    return 0;
}
auto_ptr的简单实现
//c++98
//管理权被转移之后,可能会导致被拷贝对象调用野指针
template<class T>
class auto_ptr
{
public:
    auto_ptr(T* ptr):_ptr(ptr)
    {
      
  }
    //管理权转移
    auto_ptr(auto_ptr<T>& ap)
    :_ptr(ap._ptr)
    {
        ap._ptr=nullptr;
    }
    ~auto_ptr()
    {
        cout<<"delete ptr"<<endl;
        delete _ptr;
    }
    
    //实现和指针一样
    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
private:
    T* _ptr;
};

unique_ptr

std::unique_ptr 是 C++ 标准库中提供的一种智能指针,用于管理动态分配的内存资源。它是一种独占所有权的智能指针,即同一时间只能有一个 std::unique_ptr 拥有对分配的资源的所有权。

std::auto_ptr 不同,std::unique_ptr 提供了严格的所有权语义,不支持拷贝构造和拷贝赋值操作,但支持移动构造和移动赋值操作,因此它更安全、更灵活。

以下是一个简单的示例,演示了 std::unique_ptr 的使用方式:

#include <iostream>
#include <memory>

int main() {
    std::unique_ptr<int> ptr1(new int(42));
    std::cout << "ptr1: " << *ptr1 << std::endl;

    // 尝试拷贝构造或拷贝赋值会导致编译错误
    // std::unique_ptr<int> ptr2 = ptr1;
    // std::unique_ptr<int> ptr3(ptr1);

    // 移动构造
    std::unique_ptr<int> ptr2 = std::move(ptr1);
    std::cout << "ptr2: " << *ptr2 << std::endl;

    // ptr1 不再拥有资源
    // std::cout << "ptr1: " << *ptr1 << std::endl; // 错误:ptr1 为空指针

    // 使用 std::unique_ptr 释放资源是自动的,不需要显式调用 delete

    return 0;
}
unique_ptr的实现
//c++11
//unique_ptr是如何解决,管理权被转移之后,可能会导致被拷贝对象调用野指针呢?
//就是禁止拷贝
//
template<class T>
class unique_ptr
{
public:
    unique_ptr(T* ptr):_ptr(ptr)
    {
      
  }
    
    ~unique_ptr()
    {
        cout<<"delete ptr"<<endl;
        delete _ptr;
    }
    
    //实现和指针一样
    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
    //c++11的做法
    unique_ptr(const unique_ptr<T>& up)=delete;
    unique_ptr<T>& operator=(const unique_ptr<T>& up)=delete;//赋值
    
//private:
//    //c++98的实现
//    //1.只声明不实现
//    //2.限定私有
//    unique_ptr(const unique_ptr<T>& up);
//    unique_ptr<T>& operator=(const unique_ptr<T>& up);//赋值
private:
    T* _ptr;
};

shared_ptr

std::shared_ptr 是 C++ 标准库中提供的一种智能指针,用于管理动态分配的内存资源。与 std::unique_ptr 不同,std::shared_ptr 允许多个智能指针共享对同一块内存资源的所有权,通过引用计数的方式来管理资源的生命周期。

当最后一个 std::shared_ptr 被销毁时,它所管理的资源会被释放。这种机制可以有效地避免内存泄漏,并且能够方便地在程序中共享数据结构。

以下是一个简单的示例,演示了 std::shared_ptr 的使用方式:

#include <iostream>
#include <memory>

int main() {
    // 创建一个动态分配的整数资源,被一个 shared_ptr 管理
    std::shared_ptr<int> ptr1(new int(42));
    std::cout << "ptr1: " << *ptr1 << std::endl; // 输出 42

    {
        // 在作用域内创建另一个 shared_ptr 来共享同一资源
        std::shared_ptr<int> ptr2 = ptr1;
        std::cout << "ptr2: " << *ptr2 << std::endl; // 输出 42
        std::cout << "ptr1 use count: " << ptr1.use_count() << std::endl; // 输出 2,表示两个 shared_ptr 共享同一资源
    }

    // 离开作用域后,ptr2 被销毁,但资源仍然由 ptr1 管理
    std::cout << "ptr1 use count: " << ptr1.use_count() << std::endl; // 输出 1

    // 最后一个 shared_ptr 被销毁时,资源被释放
    return 0;
}
shared_ptr的实现
//shared_ptr是通过引用计数方式来实现,拷贝和赋值
//在堆上申请一个空间作为引用计数
template<class T>
class shared_ptr
{
public:
    shared_ptr(T* ptr=nullptr)
    :_ptr(ptr),_pcount(new int(1))
    {
      
    }
    
    ~shared_ptr()
    {
        if(--(*_pcount)==0)
        {
            cout<<"delete _ptr: "<<_ptr<<endl;
            delete _ptr;
            delete _pcount;
        }
    }
    
    //实现和指针一样
    T& operator*()
    {
        return *_ptr;
    }
    T* operator->()
    {
        return _ptr;
    }
    
    //在堆上开辟一段空间
    shared_ptr(const shared_ptr<T>& sp)
    :_ptr(sp._ptr)
    ,_pcount(sp._pcount)
    {
        (*_pcount)++;
    }
    
    shared_ptr<T>& operator=(const shared_ptr<T>& sp)
    //赋值可能有很多情况
    //1)sp1赋值给sp2
    //2)自己给自己赋值
    //      1> sp1=sp1//sp1赋值给sp1
    //      2> sp1=sp2//sp1赋值给sp2
    //         sp1=sp2//sp1赋值给sp2
    {
        if(_ptr!=sp._ptr)//判断是否赋值给自己
        {
            if(--(*_pcount)==0)
            {
                delete _ptr;
                delete _pcount;
            }
            _ptr=sp._ptr;
            _pcount=sp._pcount;
            
            ++(*_pcount);
        }
        return *this;
    }
    int use_count() const
    {
        return *_pcount;
    }

    T* get() const
    {
        return _ptr;
    }
private:
    T* _ptr;
    int* _pcount;
};

weak_ptr

std::weak_ptr 也是 C++ 标准库中的智能指针,但它与 std::shared_ptr 不同,它不会增加资源的引用计数,也不会拥有资源的所有权。它通常用于解决 std::shared_ptr 的循环引用问题,以避免内存泄漏。

std::weak_ptr 可以从 std::shared_ptr 创建,但并不会影响资源的生命周期。当需要使用资源时,可以通过 std::weak_ptr 提供的 lock() 函数获1个std::shared_ptr 对象,如果资源仍然存在,则返回一个指向资源的 std::shared_ptr;如果资源已经被释放,则返回一个空的 std::shared_ptr

以下是一个简单的示例,演示了 std::weak_ptr 的使用方式:

#include <iostream>
#include <memory>

int main() {
    std::shared_ptr<int> sharedPtr = std::make_shared<int>(42);
    std::weak_ptr<int> weakPtr = sharedPtr;

    // 使用 weak_ptr 获取资源
    if (auto sharedPtr2 = weakPtr.lock()) {
        std::cout << "sharedPtr2: " << *sharedPtr2 << std::endl; // 输出 42
    } else {
        std::cout << "资源已释放" << std::endl;
    }

    // 释放原始 shared_ptr
    sharedPtr.reset();

    // 再次尝试使用 weak_ptr 获取资源
    if (auto sharedPtr3 = weakPtr.lock()) {
        std::cout << "sharedPtr3: " << *sharedPtr3 << std::endl;
    } else {
        std::cout << "资源已释放" << std::endl; // 输出 "资源已释放"
    }

    return 0;
}
weak_ptr的实现
template<class T>
    class weak_ptr
    {
    public:
        weak_ptr()
            :_ptr(nullptr)
        {}

        weak_ptr(const shared_ptr<T>& sp)
            :_ptr(sp.get())
        {}

        weak_ptr<T>& operator=(const shared_ptr<T>& sp)
        {
            _ptr = sp.get();
            return *this;
        }

        // 像指针一样
        T& operator*()
        {
            return *_ptr;
        }

        T* operator->()
        {
            return _ptr;
        }
    private:
        T* _ptr;
    };

 🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值