IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++智能指针 -> 正文阅读

[C++知识库]C++智能指针

不带引用的智能指针

/*

  • 智能指针 保证能做到资源的自动释放
  • 利用栈上的对象出作用域自动析构的特征,来做到资源的自动释放
  • 智能指针能不能定义到堆上
  • CSmartPtr *p = new CSmartPtr(new int);
  • 这是一个裸指针 也需要先delete掉
  • */

解决浅拷贝问题

template <typename T>
class CSmartPtr{
public:
    CSmartPtr(T *ptr = nullptr)
        : mptr(ptr){

    }
    ~CSmartPtr(){
        delete mptr;
    }

    T &operator* (){
        return *mptr;
    }

    T *operator->(){
        return mptr;
    }

private:
    T *mptr;
};
int main(){
    CSmartPtr<int> ptr1(new int);

    CSmartPtr<int> ptr2(ptr1);
}

这种情况会出现浅拷贝,delete俩次。

防止浅拷贝方法1 重新定义拷贝构造函数

给当前对象重新开辟一块空间,用你的值来初始化我

CSmartPtr(const CSmartPtr<T> &src){
        mptr = new T(*src.mptr);
    }
~CSmartPtr(){
        delete mptr;
        mptr = nullptr;
    }

但是这样会出现俩快资源,而用户就像管理一个资源

不带引用的智能指针

使用auto_ptr(不推荐)

auto_ptr<int> ptr1(new int);
auto_ptr<int> ptr2(ptr1);
*ptr2 = 20;
cout << *ptr1;

在这里插入图片描述
这样会报错,因为auto_ptr只会管理最后一个资源,前面的指针全部置成null;所以说在容器里面vector< auto_ptr< int >> vec1; vec2(vec1),容器的拷贝构造和容器的赋值会引起vec1里面的指针全部置成nullptr

unique_ptr

unique_ptr<const unique_ptr<T>&> = delete;
unique_ptr<T>& operator=(const unique_ptr<T>&) = delete;

unique_ptr和scoped_ptr一样都会把拷贝构造和赋值都和谐了,如果直接拷贝赋值就会报错。

c++11 右值引用 std::move得到当前变量的右值类型(右值引用的类型强转)

unique_ptr<int> p1(new int);
unique_ptr<int> p2(std::move(p1));

之所以unique_ptr可以成功是因为它带右值引用的拷贝构造函数和赋值运算符的重载函数

unique_ptr(unique_ptr<T> &&src)
unique_ptr<T>& operator=(unique_ptr<T> &&src)

带引用的智能指针

带引用技术的智能指针shared_ptr和weak_ptr
带引用计数:多个智能指针可以管理同一个资源
带引用计数:给每一个对象资源,匹配一个引用计数
智能指针 =》 资源的时候 =》 引用计数 + 1
智能指针 =》 不使用资源的时候 =》 引用计数 - 1 =》 != 0 0资源释放了

shared_ptr

// 自己实现share_ptr(线程不安全)

#include "iostream"
using namespace std;
#include "memory"
// 21点47分

template<typename T>
class RefCnt{
public:
    RefCnt(T *ptr = nullptr)
    : mptr(ptr){
        if(mptr != nullptr){
            mcount = 1;
        }
    }
    void addRef() {mcount++;} // 添加引用计数
    int delRef() {return --mcount;}
private:
    T *mptr;
    int mcount;
};

template <typename T>
class CSmartPtr{
public:
    CSmartPtr(T *ptr = nullptr)
        : mptr(ptr){
        mpRefCnt = new RefCnt<T>(mptr);
    }
//    CSmartPtr(const CSmartPtr<T> &src){
//        mptr = new T(*src.mptr);
//    }
    ~CSmartPtr(){
        if(0 == mpRefCnt->delRef()){
            delete mptr;
            mptr = nullptr;
        }

    }

    T &operator* (){
        return *mptr;
    }

    T *operator->(){
        return mptr;
    }

    //重写拷贝构造
    CSmartPtr(const CSmartPtr<T> &src)
        :mptr(src.mptr), mpRefCnt(src.mpRefCnt)
    {
        if(mptr != nullptr){
            mpRefCnt->addRef();
        }

    }

    CSmartPtr<T>& operator=(const CSmartPtr<T> &src){
        if(this == &src){
            return *this;
        }
        if(mpRefCnt->delRef() == 0){
            delete mptr;
        }

        mptr = src.mptr;
        mpRefCnt = src.mpRefCnt;
        mpRefCnt->addRef();
        return *this;
    }
private:
    T *mptr;
    RefCnt<T> *mpRefCnt;
};
int main(){
    CSmartPtr<int> p1(new int );
    CSmartPtr<int> p2(p1);
    *p1 = 20;
    cout << *p2;
}

线程安全 ++ – atomic_int

强智能指针循环引用(交叉引用)是什么问题?什么结果?怎么解决?

  • shared_ptr:强智能指针 可以改变资源的引用计数
  • weak_ptr:弱智能指针 不会改变资源的引用计数
  • weak_ptr => shared_ptr => 资源(内存)
#include "iostream"
using namespace std;
#include "memory"

class B;
class A{
public:
    A() {cout << "A()" << endl;}
    ~A() {cout << "~A()" <<endl;}
    shared_ptr<B> _ptrb;
};

class B{
public:
    B() {cout << "B()" << endl;}
    ~B() {cout << "~B()" <<endl;}
    shared_ptr<A> _ptra;
};

int main(){
    shared_ptr<A> pa(new A());
    shared_ptr<B> pb(new B());

    pa->_ptrb = pb;
    pb->_ptra = pa;

    cout << pa.use_count() << endl;
    cout << pb.use_count() << endl;
}
打印结果:
A()
B()
2
2

造成new出来的资源无法释放,资源泄露。
在这里插入图片描述

定义对象的时候,用强智能指针,引用对象的地方,使用弱智能指针

class B;
class A{
public:
    A() {cout << "A()" << endl;}
    ~A() {cout << "~A()" <<endl;}
    weak_ptr<B> _ptrb;
};

class B{
public:
    B() {cout << "B()" << endl;}
    ~B() {cout << "~B()" <<endl;}
    weak_ptr<A> _ptra;
};
打印:
A()
B()
1
1
~B()
~A()

weak_ptr

无法调用,没有提供operator* operator->
在这里插入图片描述
解决 可以用把它提升为强智能指针

void func(){
//        _ptra->testA();
        shared_ptr<A> ps = _ptra.lock(); //提升方法
        if(ps != nullptr){
            ps->testA();
        }
    }

多线程访问共享对象的线程安全问题

#include "iostream"

#include "memory"
#include "thread"
using namespace std;

class A{
public:
    A() {cout << "A()" << endl;}
    ~A() {cout << "~A()" <<endl;}
    void testA() {cout << "非常好用的方法" << endl;}

};
void handler01(A *q){
	std::this_thread::sleep_for(std::chrono::seconds(2));
    q->testA();
}
int main(){
    A *p = new A();
    thread t1(handler01, p);
    
    delete p;
    t1.join();
}
//打印
A()
~A()
非常好用的方法!

这样非常不好 因为A对象都已经释放了,但是还是可以访问。所以q在访问A对象的时候,需要侦测一下A对象是否存活。

解决

#include "iostream"

#include "memory"
#include "thread"
using namespace std;

class A{
public:
    A() {cout << "A()" << endl;}
    ~A() {cout << "~A()" <<endl;}
    void testA() {cout << "非常好用的方法" << endl;}

};
void handler01(weak_ptr<A> p){
    std::this_thread::sleep_for(std::chrono::seconds(2));
    shared_ptr<A> sp = p.lock();
    if(nullptr != sp){
        sp->testA();
    } else {
        cout << "A对象已经析构, 不能在访问" <<endl;
    }

}
int main(){
//    A *p = new A();
    {
        shared_ptr<A> p(new A());
        thread t1(handler01, weak_ptr<A>(p));
        t1.detach();
    }
    std::this_thread::sleep_for(std::chrono::seconds(20));
    return 0;


//    delete p;
//    t1.join();
}
//打印
A()
~A()
A对象已经析构, 不能在访问
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-13 11:37:19  更:2022-05-13 11:37:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/11 2:36:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码