c++ 智能指针

c++ 有三种智能指针:

  • shared_ptr
  • weak_ptr
  • unique_ptr

头文件

关于 auto_ptr 指针

C++98 提供了 auto_ptr 模板的解决方案, 在 c++11 被弃用,c++17中彻底移除,用 unique_ptr 代替

auto_ptr 被弃用的主要原因:
 1.复制或者赋值都会改变资源的所有权,在STL容器中有重大风险

auto_ptr<string> p1(new string("I'm P1!"));
auto_ptr<string> p2(new string("I'm P2."));
vector<auto_ptr<string>> vec;
// 必须使用move修饰成右值,才可以进行插入容器中
vec.push_back(move(p1));
vec.push_back(move(p2));

cout << "vec[0]:" <<  *vec.[0] << endl; // 输出:I'm p1
cout << "vec[1]:" <<  *vec[1] << endl; // 输出:I'm p2

// p2赋值给p1后,首先p1会先将自己原先托管的指针释放掉,然后接收托管p2所托管的指针,
// 然后p2所托管的指针指向NULL,也就是p1托管了p2托管的指针,而p2放弃了托管。
p1 = p2;

// 风险来了:
vec[0] = vec[1];
cout << "vec[0]:" << *vec[0] << endl; // 输出: I'm p2
cout << "vec[1]:" << *vec[1] << endl; // ERROR, vec[1] 此时指向 nullptr

 2.不支持对象数组的内存管理

auto_ptr<int[]> array(new int[5]); // ERROR, 不能这样定义

unique_ptr

C++11用更严谨的 unique_ptr 取代了auto_ptr。

unique_ptr 用法:
 uniquer_ptr 是独占指针,只能有一个 unique_ptr 指针指向某个对象
 通过指针占有并管理另一对象,并在 unique_ptr 离开作用域时释放该对象。
 unique_ptr 可以不占有对象,此时 unique_ptr 为空

unique_ptr 有两个版本:

  1. 管理单个对象(例如以 new 分配)
  2. 管理动态分配的对象数组(例如以 new[] 分配)

类可以移动构造 (MoveConstructible) 和 移动赋值 (MoveAssignable);不能复制构造 (CopyConstructible) 和 复制赋值 (CopyAssignable) 。(只能有一个 unique_ptr 指针指向某个对象)

构造方式

#include 
#include 
using namespace std;
 
struct Foo { // object to manage
    Foo() { cout << "Foo ctor" << endl; }
    Foo(const Foo&) { cout << "Foo copy ctor" << endl; }
    Foo(Foo&&) { cout << "Foo move ctor" << endl; }
    ~Foo() { cout << "~Foo dtor" << endl; }
};
 
struct D { // deleter
    D() {};
    D(const D&) { cout << "D copy ctor" << endl; }
    D(D&) { cout << "D non-const copy ctor" << endl;}
    D(D&&) { cout << "D move ctor " << endl; }
    void operator()(Foo* p) const {
        cout << "D is deleting a Foo" << endl;
        delete p;
    };
};
 
int main()
{
    cout << "Example constructor(1)..." << endl;
    unique_ptr<Foo> up1;  // up1 is empty
    unique_ptr<Foo> up1b(nullptr);  // up1b is empty
 
    cout << "Example constructor(2)..." << endl;
    {
        unique_ptr<Foo> up2(new Foo); //up2 now owns a Foo
    } // Foo deleted
 
    cout << "Example constructor(3)..." << endl;
    D d;
    {  // deleter type is not a reference
       unique_ptr<Foo, D> up3(new Foo, d); // deleter copied
    }
    {  // deleter type is a reference 
       unique_ptr<Foo, D&> up3b(new Foo, d); // up3b holds a reference to d
    }
 
    cout << "Example constructor(4)..." << endl;
    {  // deleter is not a reference 
       unique_ptr<Foo, D> up4(new Foo, D()); // deleter moved
    }
 
    cout << "Example constructor(5)..." << endl;
    {
       unique_ptr<Foo> up5a(new Foo);
       unique_ptr<Foo> up5b(move(up5a)); // ownership transfer
    }
 
    cout << "Example constructor(6)..." << endl;
    {
        unique_ptr<Foo, D> up6a(new Foo, d); // D is copied
        unique_ptr<Foo, D> up6b(move(up6a)); // D is moved
 
        unique_ptr<Foo, D&> up6c(new Foo, d); // D is a reference
        unique_ptr<Foo, D> up6d(move(up6c)); // D is copied
    }
 
    cout << "Example array constructor..." << endl;
    {
        unique_ptr<Foo[]> up(new Foo[3]);
    } // three Foo objects deleted
}

注意:

 只有非 const 的 unique_ptr 能转移被管理对象的所有权给另一 unique_ptr 。若对象的生存期为 const unique_ptr 所管理,则它被限定在创建指针的作用域中。

shared_ptr

共享指针,是为多个所有者可能必须管理对象在内存中的生命周期的方案设计。 在初始化一个 shared_ptr 之后,可复制它,按值将其传入函数参数,然后将其分配给其他 shared_ptr 实例。 所有实例均指向同一个对象,并共享对一个“控制块”(每当新的 shared_ptr 添加、超出范围或重置时增加和减少引用计数)的访问权限。 当引用计数达到零时,控制块将删除内存资源和自身。

简单实现 shared_ptr

#include 
#include 
using namespace std;

template <typename T>
class myShared_ptr{
public:
    myShared_ptr(T* ptr = nullptr)
        : _ptrCount(new int(1)),
          _ptr(ptr),
          _mutex(new mutex()) {}
    myShared_ptr(myShared_ptr& sp)
        : _ptrCount(sp._ptrCount),
          _ptr(sp._ptr),
          _mutex(sp._mutex) {}
    ~myShared_ptr() {
        release();
    }

    myShared_ptr<T> & operator=(const myShared_ptr<T>& sp) {
        if (_ptr != sp._ptr) {
            release();
            _ptr = sp._ptr;
            _ptrCount = sp._ptrCount;
            _mutex = sp._mutex;
            addCount();
        }
        return *this;
    }
    T&  operator*() { return *_ptr; }
    T*  operator->() { return _ptr; }
    int useCount() { return *_ptrCount; }
    T*  get() { return _ptr; }


private:
    void release() {
        _mutex->lock();
        bool flagMutex = false;
        if (--(*_ptrCount) == 0) {
            delete _ptrCount;
            delete _ptr;
            flagMutex = true;
        }
        _mutex->unlock();
        if (flagMutex)
            delete _mutex;
    }

    void addCount() {
        _mutex->lock();
        ++(*_ptrCount);
        _mutex->unlock();
    }

private:
    int* _ptrCount;
    T* _ptr;
    mutex* _mutex;
};

class B;
class A {
public:
    A() { cout << "constuctor A" << endl; }
    ~A() { cout << "deconstuctor A" << endl; }
};

class B {
public:
    B() { cout << "constuctor B" << endl; }
    ~B() { cout << "deconstuctor B" << endl; }
};

int main()
{
    A *a = new A();
    B *b = new B();
    myShared_ptr<A> aPtr(a);
    myShared_ptr<B> bPtr(b);

    cout << aPtr.useCount() << endl;
    cout << bPtr.useCount() << endl;
    return 0;
}

// 输出
constuctor A
constuctor B
1
1
deconstuctor B
deconstuctor A

weak_ptr

为了解决 shared_ptr 循环引用的问题而引入。
Weak_ptr允许共享,但不拥有一个对象。 它的对象是由shared_ptr创建的

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

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

int main()
{
    shared_ptr<A> aPtr = make_shared<A>();
    shared_ptr<B> bPtr = make_shared<B>();

    cout << aPtr.use_count() << endl;  // 输出 1
    cout << bPtr.use_count() << endl;  // 输出 1
    return 0;
}

//输出
constuctor A
constuctor B
1
1
deconstuctor B
deconstuctor A

此时 A 和 B 正常析构。

int main()
{
    shared_ptr<A> aPtr = make_shared<A>();
    shared_ptr<B> bPtr = make_shared<B>();

    cout << aPtr.use_count() << endl;  // 输出 1
    cout << bPtr.use_count() << endl;  // 输出 1

    aPtr->_b = bPtr;
    bPtr->_a = aPtr;

    cout << aPtr.use_count() << endl; // 输出 2
    cout << bPtr.use_count() << endl; // 输出 2

    return 0;
}
// 输出
constuctor A
constuctor B
1
1
2
2

没有调用 A 和 B 的析构函数。aPtr 和 bPtr 的引用计数都为 2。
此时就会造成内存泄漏,所以需要 weak_ptr 指针

class B;
class A {
public:
    weak_ptr<B> _b; // 这里把 shared_ptr 换成 weak_ptr
    A() { cout << "constuctor A" << endl; }
    ~A() { cout << "deconstuctor A" << endl; }
};

class B {
public:
    weak_ptr<A> _a;  // 这里把 shared_ptr 换成 weak_ptr
    B() { cout << "constuctor B" << endl; }
    ~B() { cout << "deconstuctor B" << endl; }
};

int main()
{
    shared_ptr<A> aPtr = make_shared<A>();
    shared_ptr<B> bPtr = make_shared<B>();

    cout << aPtr.use_count() << endl;  // 输出 1
    cout << bPtr.use_count() << endl;  // 输出 1

    aPtr->_b = bPtr;
    bPtr->_a = aPtr;

    cout << aPtr.use_count() << endl;
    cout << bPtr.use_count() << endl; 

    return 0;
}

// 输出
constuctor A
constuctor B
1
1
1
1
deconstuctor B
deconstuctor A

你可能感兴趣的:(c++,开发语言)