C++智能指针

C++智能指针,第1张

文章目录
  • 不带引用的智能指针
    • 解决浅拷贝问题
      • 防止浅拷贝方法1 重新定义拷贝构造函数
      • 不带引用的智能指针
      • 使用auto_ptr(不推荐)
      • unique_ptr
      • 带引用的智能指针
      • shared_ptr
        • 线程安全 ++ -- atomic_int
      • 强智能指针循环引用(交叉引用)是什么问题?什么结果?怎么解决?
        • 定义对象的时候,用强智能指针,引用对象的地方,使用弱智能指针
        • weak_ptr
    • 多线程访问共享对象的线程安全问题
      • 解决

不带引用的智能指针

/*

  • 智能指针 保证能做到资源的自动释放
  • 利用栈上的对象出作用域自动析构的特征,来做到资源的自动释放
  • 智能指针能不能定义到堆上
  • CSmartPtr *p = new CSmartPtr(new int);
  • 这是一个裸指针 也需要先delete掉
  • */
解决浅拷贝问题
template 
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 ptr1(new int);

    CSmartPtr ptr2(ptr1);
}

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

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

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

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

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

不带引用的智能指针 使用auto_ptr(不推荐)
auto_ptr ptr1(new int);
auto_ptr ptr2(ptr1);
*ptr2 = 20;
cout << *ptr1;


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

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

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

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

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

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

unique_ptr(unique_ptr &&src)
unique_ptr& operator=(unique_ptr &&src)
带引用的智能指针

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

shared_ptr

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

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

template
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 
class CSmartPtr{
public:
    CSmartPtr(T *ptr = nullptr)
        : mptr(ptr){
        mpRefCnt = new RefCnt(mptr);
    }
//    CSmartPtr(const CSmartPtr &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 &src)
        :mptr(src.mptr), mpRefCnt(src.mpRefCnt)
    {
        if(mptr != nullptr){
            mpRefCnt->addRef();
        }

    }

    CSmartPtr& operator=(const CSmartPtr &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 *mpRefCnt;
};
int main(){
    CSmartPtr p1(new int );
    CSmartPtr 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()" <_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()" <
打印:
A()
B()
1
1
~B()
~A()
weak_ptr

无法调用,没有提供operator* operator->

解决 可以用把它提升为强智能指针

void func(){
//        _ptra->testA();
        shared_ptr 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()" <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()" <testA();
    } else {
        cout << "A对象已经析构, 不能在访问" <
//打印
A()
~A()
A对象已经析构, 不能在访问

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/920665.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-16
下一篇2022-05-16

发表评论

登录后才能评论

评论列表(0条)