C++11智能指针

智能指针主要管理堆上分配的内存,将普通指针封装为一个栈对象,当栈的生命周期结束后,会调用析构函数释放掉申请的内存空间,来防止内存泄漏。通常采用计数器

auto_ptr

c++98的智能指针,c++11不再用,存在潜在的内存崩溃问题;如下代码:

auto_ptr<string> p1 (new string ("auto_ptr测试。")); 
auto_ptr<string> p2; 
p2 = p1; //auto_ptr不会报错.

unique_ptr

unique_ptr时独占的智能指针,替代C++98中的auto_ptr,可保证一个对象只能一个unique_ptr指针指向该对象。

unique_ptr<string> p3 (new string ("unique_ptr测试。"));
unique_ptr<string> p4;
p4 = p3;//此时会报错!!

unique_ptr可以通过零时右值对象进行赋值,也可以通过移动语义std::move()函数实现赋值,move()函数其实就是右值引用,属于浅拷贝

unique_ptr<string> pu1(new string ("unique_ptr测试1")); 
unique_ptr<string> pu2; 
pu2 = pu1;                                      // #1 不允许
unique_ptr<string> pu3; 
pu3 = unique_ptr<string>(new string ("unique_ptr测试1"));   // #2 允许

unique_ptr<string> ps1, ps2;
ps1 = make_unique<string>("xiaoyan");
ps2 = move(ps1);                    //所有权的转移
ps1 = make_unique<string>("yu");
cout << *ps2 << *ps1 << endl;

shared_ptr

shared_ptr是共享智能指针,允许多个shared_ptr智能指针同时指向一个对象,使用计数器的方式来表明有多少个共享指针。可通过成员函数use_count()来查询当前共享的个数。

可通过auto_ptr, unique_ptr,weak_ptr及new来构造,通过release()来释放当前执政的所有权,同时计数器减一,当计数器为0时,内存资源释放。

对shared_ptr进行初始化时不能将一个普通指针直接赋值给智能指针,因为一个是指针,一个是类。可以通过make_shared函数或者通过构造函数传入普通指针。并可以通过get函数获得普通指针。

成员函数

use_count():返回该对象引用的次数

unique():返回是否时独占对象的所有权,即use_count为1

swap():交换连个shared_ptr的对象

reset():放弃内部对象的所有权或拥有对象的变更, 会引起原有对象的引用计数的减少

get():返回内部对象,和直接只用对象一样

示例:

int main()
{
	string *s1 = new string("s1");

	shared_ptr<string> ps1(s1);
	shared_ptr<string> ps2;
	ps2 = ps1;

	cout << ps1.use_count()<<endl;	//2
	cout<<ps2.use_count()<<endl;	//2
	cout << ps1.unique()<<endl;	//0

	string *s3 = new string("s3");
	shared_ptr<string> ps3(s3);

	cout << (ps1.get()) << endl;	//033AEB48
	cout << ps3.get() << endl;	//033B2C50
	swap(ps1, ps3);	//交换所拥有的对象
	cout << (ps1.get())<<endl;	//033B2C50
	cout << ps3.get() << endl;	//033AEB48

	cout << ps1.use_count()<<endl;	//1
	cout << ps2.use_count() << endl;	//2
	ps2 = ps1;
	cout << ps1.use_count()<<endl;	//2
	cout << ps2.use_count() << endl;	//2
	ps1.reset();	//放弃ps1的拥有权,引用计数的减少
	cout << ps1.use_count()<<endl;	//0
	cout << ps2.use_count()<<endl;	//1
}

weak_ptr

shared_ptr循环引用,会造成内存泄漏;

shared_ptr是对对象的强引用,负责控制对象的生命周期,weak_ptr是对对象的弱引用,不控制对象的生命周期。

weak_ptr是用来协助shared_ptr的智能指针,它只能通过一个shared_ptr或者weak_ptr对象来构造,它的构造和析构不会引起计数器的改变。

weak_ptr可以通过lock()函数实现shared_ptr的转换

class B;	//声明
class A
{
public:
	shared_ptr<B> pb_;
	~A()
	{
		cout << "A delete\n";
	}
};

class B
{
public:
	shared_ptr<A> pa_;
	~B()
	{
		cout << "B delete\n";
	}
};

void fun()
{
	shared_ptr<B> pb(new B());
	shared_ptr<A> pa(new A());
	cout << pb.use_count() << endl;	//1
	cout << pa.use_count() << endl;	//1
	pb->pa_ = pa;
	pa->pb_ = pb;
	cout << pb.use_count() << endl;	//2
	cout << pa.use_count() << endl;	//2
}

int main()
{
	fun();
	return 0;
}

上面代码中存在相互引用,当智能指针跳出作用域时,引用次数只会减一,导致资源没有被释放,内存泄漏。

把类A中的引用的类B的智能指针换成weak_ptr智能指针,类B中引用类A的同样替换成weak_ptr,就可以避免内存泄漏。

成员函数:

expired(): 用于检测所管理的对象是否已经释放, 如果已经释放, 返回 true; 否则返回 false。

lock(): 用于获取所管理的对象的强引用(shared_ptr). 如果 expired 为 true, 返回一个空的 shared_ptr; 否则返回一个 shared_ptr, 其内部对象指向与 weak_ptr 相同。

use_count ():返回与 shared_ptr 共享的对象的引用计数;

reset(): 将 weak_ptr 置空;

weak_ptr 支持拷贝或赋值, 但不会影响对应的 shared_ptr 内部对象的计数。

weak_ptr和shared_ptr的简单实现

weak_ptr使用时,作为share_ptr的弱引用,期实现依赖于counter的计数器类和share_ptr的复制、构造

cunter实现

class Counter
{
public:
    Counter() : s(0), w(0){};
    int s;	//share_ptr的引用计数
    int w;	//weak_ptr的引用计数
};

 

shared_ptr的简单实现

template <class T>
class WeakPtr; //为了用weak_ptr的lock(),来生成share_ptr用,需要拷贝构造用

template <class T>
class SharePtr
{
public:
    SharePtr(T *p = 0) : _ptr(p)
    {
        cnt = new Counter();
        if (p)
            cnt->s = 1;
        cout << "in construct " << cnt->s << endl;
    }
    ~SharePtr()
    {
        release();
    }

    SharePtr(SharePtr<T> const &s)
    {
        cout << "in copy con" << endl;
        _ptr = s._ptr;
        (s.cnt)->s++;
        cout << "copy construct" << (s.cnt)->s << endl;
        cnt = s.cnt;
    }
    SharePtr(WeakPtr<T> const &w) //为了用weak_ptr的lock(),来生成share_ptr用,需要拷贝构造用
    {
        cout << "in w copy con " << endl;
        _ptr = w._ptr;
        (w.cnt)->s++;
        cout << "copy w  construct" << (w.cnt)->s << endl;
        cnt = w.cnt;
    }
    SharePtr<T> &operator=(SharePtr<T> &s)
    {
        if (this != &s)
        {
            release();
            (s.cnt)->s++;
            cout << "assign construct " << (s.cnt)->s << endl;
            cnt = s.cnt;
            _ptr = s._ptr;
        }
        return *this;
    }
    T &operator*()
    {
        return *_ptr;
    }
    T *operator->()
    {
        return _ptr;
    }
    friend class WeakPtr<T>; //方便weak_ptr与share_ptr设置引用计数和赋值

protected:
    void release()
    {
        cnt->s--;
        cout << "release " << cnt->s << endl;
        if (cnt->s < 1)
        {
            delete _ptr;
            if (cnt->w < 1)
            {
                delete cnt;
                cnt = NULL;
            }
        }
    }

private:
    T *_ptr;
    Counter *cnt;
};

weak_ptr的简单实现

template <class T>
class WeakPtr
{
public: //给出默认构造和拷贝构造,其中拷贝构造不能有从原始指针进行构造
    WeakPtr()
    {
        _ptr = 0;
        cnt = 0;
    }
    WeakPtr(SharePtr<T> &s) : _ptr(s._ptr), cnt(s.cnt)
    {
        cout << "w con s" << endl;
        cnt->w++;
    }
    WeakPtr(WeakPtr<T> &w) : _ptr(w._ptr), cnt(w.cnt)
    {
        cnt->w++;
    }
    ~WeakPtr()
    {
        release();
    }
    WeakPtr<T> &operator=(WeakPtr<T> &w)
    {
        if (this != &w)
        {
            release();
            cnt = w.cnt;
            cnt->w++;
            _ptr = w._ptr;
        }
        return *this;
    }
    WeakPtr<T> &operator=(SharePtr<T> &s)
    {
        cout << "w = s" << endl;
        release();
        cnt = s.cnt;
        cnt->w++;
        _ptr = s._ptr;
        return *this;
    }
    SharePtr<T> lock()
    {
        return SharePtr<T>(*this);
    }
    bool expired()
    {
        if (cnt)
        {
            if (cnt->s > 0)
            {
                cout << "empty" << cnt->s << endl;
                return false;
            }
        }
        return true;
    }
    friend class SharePtr<T>; //方便weak_ptr与share_ptr设置引用计数和赋值
    
protected:
    void release()
    {
        if (cnt)
        {
            cnt->w--;
            cout << "weakptr release" << cnt->w << endl;
            if (cnt->w < 1 && cnt->s < 1)
            {
                //delete cnt;
                cnt = NULL;
            }
        }
    }

private:
    T *_ptr;
    Counter *cnt;
};

unique_ptr简单实现

template <typename T>
class UniquePointer 
{
public:
	using Pointer = T*;
	using Reference = T&;

	UniquePointer() :_ptr(nullptr) {}
	UniquePointer(Pointer ptr) :_ptr(ptr) {}
	UniquePointer(UniquePointer&& other) :_Ptr(other)
	{
		other._ptr = nullptr;
	}

	UniquePointer& operator=(const UniquePointer&& other)
	{
		_ptr = other._ptr;
		other._ptr = nullptr;
		return *this;
	}

	UniquePointer(const UniquePointer &) = delete;
	UniquePointer& operator=(const UniquePointer&) = delete;

	~UniquePointer()
	{
		if (_ptr!=nullptr)
		{
			delete _ptr;
		}
	}

	operator bool()
	{
		return _ptr != nullptr;
	}

	Pointer get()
	{
		return _ptr;
	}

	Reference operator *()
	{
		return *_ptr;
	}

	Pointer operator ->()
	{
		return _ptr;
	}

	void reset(Pointer ptr = nullptr)
	{
		if (_ptr != nullptr)
		{
			delete _ptr;
		}
		_ptr = ptr;
	}
private:
	Pointer _ptr;
};

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值