智能指针

原理:

智能指针是一个类,这个类的构造函数中传入一个普通指针,析构函数中释放传入的指针。智能指针的类都是栈上的对象,所以当函数(或程序)结束时会自动被释放。方便管理堆内存。
智能指针是利用RAII(资源获取即初始化)技术对普通指针进行封装,使智能指针实质是一个对象,行为表现的像一个指针。

常用的智能指针:

1、shared_ptr:
基于引用计数的智能指针。可随意赋值,当内存引用计数为0时内存被释放。支持多个指针指向相同的对象。shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁。

初始化:智能指针是模板类,可以指定类型,传入指针通过构造函数初始化。也可以使用make_shared函数初始化。不能将指针直接赋值给一个智能指针,因为智能指针是类,不能用指针赋值。
例如:std::shared_ptr p4 = new int(1);写法错误
拷贝和赋值:拷贝使对象的引用计数加1,赋值使原对象(左侧)引用计数减1,新对象(右侧)引用计数加1,当计数为0时,自动释放内存。
get函数:获取原始指针,不要用一个原始指针初始化多个shared_ptr,否则会造成二次释放同一内存。

#include 
#include 

int main() {
    {
        int a = 10;
        std::shared_ptr ptra = std::make_shared(a);
        std::shared_ptr ptra2(ptra); //copy
        std::cout << ptra.use_count() << std::endl;  // 2

        int b = 20;
        int *pb = &a;
        //std::shared_ptr ptrb = pb;  // error 不能用指针赋值类
        std::shared_ptr ptrb = std::make_shared(b);
        ptra2 = ptrb; // assign ptra2由ptra位置变为指向ptrb
        pb = ptrb.get(); // 获取原始指针

        std::cout << ptra.use_count() << std::endl;  // 1
        std::cout << ptrb.use_count() << std::endl;  // 2
    }
}

2、unique_ptr:
“唯一”拥有所指对象。同一时刻只能有一个unique_ptr指向给定对象,禁止拷贝语义、只有移动语义。在出现异常的情况下,动态资源能得到释放。

创建:通过构造函数指定
重新指定:reset方法
释放所有权:release方法
移动语义转移所有权:std::move

#include 
#include 

int main() {
    {
        std::unique_ptr uptr(new int(10));  //绑定动态对象
        //std::unique_ptr uptr2 = uptr;  //不能赋值,编译出错
        //std::unique_ptr uptr2(uptr);  //不能拷贝
        std::unique_ptr uptr2 = std::move(uptr); //转移所有权,uptr无效指针
        uptr2.release(); //释放所有权
    }
    /超过uptr的作用域,內存释放
}

3、weak_ptr:
弱引用,只引用,不计数,没有重载operator*和->,对shared_ptr资源观测。针对shared_ptr互相引用形成环(循环引用),两个指针指向的内存都无法释放的问题。需要手动打破循环引用或使用weak_ptr。

构造:从一个shared_ptr或者另一个weak_ptr对象构造。
观测资源的引用计数:成员函数use_count()。
被观测的资源是否存在:成员函数expired(),功能等价于use_count()==0,但更快。
从被观测的shared_ptr获得一个可用的shared_ptr对象:成员函数lock(), 操作资源。当expired()==true的时候,lock()函数返回一个存储空指针的shared_ptr。
注意:如果一块内存被shared_ptr和weak_ptr同时引用,所有shared_ptr析构后,不管还有没有weak_ptr引用该内存,内存也会被释放。所以weak_ptr不保证它指向的内存一定是有效的,在使用之前需要检查weak_ptr是否为空指针。

#include 
#include 

int main() {
    {
        std::shared_ptr sh_ptr = std::make_shared(10);
        std::cout << sh_ptr.use_count() << std::endl;  // 1

        std::weak_ptr wp(sh_ptr);
        std::cout << wp.use_count() << std::endl;  // 1

        if(!wp.expired()){
            std::shared_ptr sh_ptr2 = wp.lock(); //get another shared_ptr
            *sh_ptr = 100;
            std::cout << wp.use_count() << std::endl;  // 2
        }
    }
    //delete memory
}

循环引用例子如下:
错误例子:

#include 
#include 

class Child;
class Parent;

class Parent {
private:
    std::shared_ptr ChildPtr;
public:
    void setChild(std::shared_ptr child) {
        this->ChildPtr = child;
    }
    void doSomething() {
        if (this->ChildPtr.use_count()) {

        }
    }
    ~Parent() {
    }
};

class Child {
private:
    std::shared_ptr ParentPtr;
public:
    void setPartent(std::shared_ptr parent) {
        this->ParentPtr = parent;
    }
    void doSomething() {
        if (this->ParentPtr.use_count()) {

        }
    }
    ~Child() {
    }
};

int main() {
    std::weak_ptr wpp;
    std::weak_ptr wpc;
    {  // {}代表作用域,出作用域以下p和c应该被销毁
        std::shared_ptr p(new Parent);   // 1
        std::shared_ptr c(new Child);   // 1
        p->setChild(c);   // 2
        c->setPartent(p);   // 2
        wpp = p;
        wpc = c;
        std::cout << p.use_count() << std::endl; // 2
        std::cout << c.use_count() << std::endl; // 2
    }  // 出作用域时对象p和c没销毁,每个count只减少一次
    std::cout << wpp.use_count() << std::endl;  // 1
    std::cout << wpc.use_count() << std::endl;  // 1
    return 0;
} 

正确做法:

#include 
#include 

class Child;
class Parent;

class Parent {
private:
    //std::shared_ptr ChildPtr;
    std::weak_ptr ChildPtr;
public:
    void setChild(std::shared_ptr child) {
        this->ChildPtr = child;
    }
    void doSomething() {
        //new shared_ptr
        if (this->ChildPtr.lock()) {

        }
    }
    ~Parent() {
    }
};

class Child {
private:
    std::shared_ptr ParentPtr;
public:
    void setPartent(std::shared_ptr parent) {
        this->ParentPtr = parent;
    }
    void doSomething() {
        if (this->ParentPtr.use_count()) {

        }
    }
    ~Child() {
    }
};

int main() {
    std::weak_ptr wpp;
    std::weak_ptr wpc;
    {
        std::shared_ptr p(new Parent); // 1
        std::shared_ptr c(new Child); // 1
        p->setChild(c); // c = 1
        c->setPartent(p); // p = 2
        wpp = p;
        wpc = c;
        std::cout << p.use_count() << std::endl; // 2
        std::cout << c.use_count() << std::endl; // 1
    } // c只有1,1-->0,销毁c对象时调用child的析构函数,会对p销毁一次,而p对象本身会销毁一次,所以也是0
    std::cout << wpp.use_count() << std::endl;  // 0
    std::cout << wpc.use_count() << std::endl;  // 0
    return 0;
}

智能指针实现:

#include 
#include 

template
class SmartPointer {
private:
    T* _ptr;
    size_t* _count;
public:
    SmartPointer(T* ptr = nullptr) : _ptr(ptr) {
        if (_ptr) {
            _count = new size_t(1);
        } else {
            _count = new size_t(0);
        }
    }

    SmartPointer(const SmartPointer& ptr) {
        if (this != &ptr) {
            this->_ptr = ptr._ptr;
            this->_count = ptr._count;
            (*this->_count)++;
        }
    }

    SmartPointer& operator=(const SmartPointer& ptr) {
        if (this->_ptr == ptr._ptr) {
            return *this;
        }

        if (this->_ptr) {
            (*this->_count)--;
            if (*this->_count == 0) {
                delete this->_ptr;
                delete this->_count;
            }
        }

        this->_ptr = ptr._ptr;
        this->_count = ptr._count;
        (*this->_count)++;
        return *this;
    }

    T& operator*() {
        assert(this->_ptr == nullptr);
        return *(this->_ptr);

    }

    T* operator->() {
        assert(this->_ptr == nullptr);
        return this->_ptr;
    }

    ~SmartPointer() {
        (*this->_count)--;
        if (*this->_count == 0) {
            delete this->_ptr;
            delete this->_count;
        }
    }

    size_t use_count(){
        return *this->_count;
    }
};

int main() {
    {
        SmartPointer sp(new int(10));
        SmartPointer sp2(sp);
        SmartPointer sp3(new int(20));
        std::cout << sp.use_count() << std::endl;
        std::cout << sp3.use_count() << std::endl;
        sp2 = sp3;
        std::cout << sp.use_count() << std::endl;
        std::cout << sp3.use_count() << std::endl;
    }
    //delete operator
}

你可能感兴趣的:(智能指针)