zoukankan      html  css  js  c++  java
  • C++11智能指针 share_ptr,unique_ptr,weak_ptr用法

    0x01  智能指针简介

        所谓智能指针(smart pointer)就是智能/自动化的管理指针所指向的动态资源的释放。它是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动态分配的对象,防止内存泄露。它的一种通用实现技术是使用引用计数(reference count)。

        使用智能指针需要头文件 #include<memory> 。

         C++11从boost库中引入了unique_ptr, shared_ptr, weak_ptr,并舍弃了c98的auto_ptr。

    0x02  auto_ptr

           C++11从boost库中引入了unique_ptr, shared_ptr, weak_ptr,并舍弃了c98的auto_ptr。

          C++标准程序库描述:“auto_ptr是一种智能指针,帮助程序员防止'被异常抛出时发生资源泄露'”。它在对象析构的时候自动释放资源,并模仿了原始指针的操作,重载了operator*和operator->,允许程序员向使用原始指针一样使用auto_ptr(但是没有重载所有的指针算术运算),并减少程序员显示的处理异常发生时代码的复杂度与失误。

       该指针的定义形式:auto_ptr<type> ptr(new type()); 其中 type 是指针指向的类型。

         例如:auto_ptr<int> ptr(new int(4));

       当然也可以先定义,后赋值:auto_ptr<int> ptr;ptr = auto_ptr<int>(new int (4));

         auto_ptr的作用:作用1:保证一个对象在某个时间只能被一个该种类型的智能指针所指向,就是通常所说的对象所有权。

                作用2:对指向的对象自动释放的作用。   

    #include "stdafx.h"
    #include <Windows.h>
    #include <memory>
    #include <iostream>
    using namespace std;
    struct MyStruct
    {
    	MyStruct() { cout << "MyStruct()
    "; }
    	~MyStruct() { cout << "~MyStruct()
    "; }
    	int i;
    	int j;
    };
    
    int main()
    {
    	auto_ptr<MyStruct> ptr(new MyStruct);
    	ptr->i = 1;
    	ptr->j = 2;
    	(*ptr).i = 3;
    	(*ptr).j = 4;
        return 0;
    }
    

       auto_ptr是严格的拥有权类智能指针,使用时需要注意以下几点:

    1. auto_ptr之间不能共享拥有权
    2. auto_ptr对象通过赋值或构造转移拥有权,一旦拥有权转移,此auto_ptr所拥有的将是一个原始指针
    3. auto_ptr不适用于array
    4. auto_ptr不满足STL对容器元素的要求,因此不适用于STL容器。因为在拷贝和赋值之后,新的auto_ptr和旧的auto_ptr对象并不相等。
    5. 如果要阻止拥有权的转移,则应该在停止转移之前,将auto_ptr声明为const
    6. 不要使用auto_ptr的引用作为实参:因为你不知道拥有权到底有没有转移。如果你不需要转移拥有权,请使用const auto_ptr<class> &

    0x03  shared_ptr

         shared_ptr采用引用计数的方式管理所指向的对象。当有一个新的shared_ptr指向同一个对象时(复制shared_ptr等),引用计数加1。当shared_ptr离开作用域时,引用计数减1。当引用计数为0时,释放所管理的内存。

    这样做的好处在于减轻了程序员手动释放内存的负担。之前,为了处理程序中的异常情况,往往需要将指针手动封装到类中,通过析构函数来释放动态分配的内存;现在这一过程就可以交由shared_ptr完成了。

         一般使用make_shared来获得shared_ptr。

         

    void Shared_PtrTest()
    {
    		//shared_ptr Test
    	//Test One
    	cout << "test shared_ptr base usage:" << endl;
    	shared_ptr<string> v1 = make_shared<string>("");
    	if (v1 && v1->empty())
    		*v1 = "Chronic";
    
    	auto v2 = make_shared<string>("LSH");
    	cout << *v1 << ' ' << *v2 << endl;
    
    	cout << "test shared_ptr use_count:" << endl;
    	cout << "v1 ReferenceCount:" << v1.use_count() << "	v2 ReferenceCount:" << v2.use_count() << endl;
    
    	auto v3 = v2;
    	cout << "v1 ReferenceCount:" << v1.use_count() << "	v2 ReferenceCount:" << v2.use_count() << "	v3 ReferenceCount:" << v3.use_count() << endl;
    	v2 = v1;
    	cout << "v1 ReferenceCount:" << v1.use_count() << "	v2 ReferenceCount:" << v2.use_count() << "	v3 ReferenceCount:" << v3.use_count() << endl;
    
    	//Test Two
    	//使用一个new表达式返回的指针进行初始化。
    	cout << "test shared_ptr and new:" << endl;
    	shared_ptr<int> p4(new int(1024));
    	//shared_ptr<int> p5 = new int(1024); // 错误
    	cout << *p4 << endl;
    
    	//Test Three
    	//不可混用new和shared_ptr!
    	cout << "不可混用new和shared_ptr!" << endl;
    	shared_ptr<int> p5(new int(1024));
    	process(p5);
    	int v5 = *p5;
    	cout << "v5: " << v5 << endl;
    
    	int *p6 = new int(1024);
    	//shared_ptr<int> p6(new int(1024));  正确做法
    	process(shared_ptr<int>(p6));
    	int v6 = *p6;
    	cout << "v6: " << v6 << endl;
    	/*
    	输出结果:
    	不可混用new和shared_ptr!
    	in process use_count:2
    	v5: 1024
    	in process use_count:1
    	v6: -572662307
    	*/
    
    	//Test Four
    	//shared_ptr可以通过reset方法重置指向另一个对象,此时原对象的引用计数减一。
    	//shared_ptr<string> v1 = make_shared<string>("LSH");
    	cout << "test shared_ptr reset:" << endl;
    	cout << "p1 cnt:" << v1.use_count() << endl;
    	v1.reset(new string("LSH Reset"));
    	cout << "p1 cnt:" << v1.use_count() << endl;
    }
    

      

    0x04  unique_ptr

        unique_ptr对于所指向的对象,如其名所示,是独占的。所以,不可以对unique_ptr进行拷贝、赋值等操作,但是可以通过release函数在unique_ptr之间转移控制权。

        对于拷贝的限制,有两个特殊情况,即unique_ptr可以作为函数的返回值和参数使用,这时虽然也有隐含的拷贝存在,但是并非不可行的。

        

    void Unique_PtrTest()
    {
    	//Test One
    	//unique_ptr对于所指向的对象,正如其名字所示,是 独占 的。
    	//所以,不可以对unique_ptr进行拷贝、赋值等操作,但是可以通过release函数在unique_ptr之间转移控制权。
    	cout << "test unique_ptr base usage:" << endl;
    	unique_ptr<int> up1(new int(1024));
    	cout << "up1: " << *up1 << endl;
    	unique_ptr<int> up2(up1.release());
    	cout << "up2: " << *up2 << endl;
    	//unique_ptr<int> up3(up1); // 错误,不可进行拷贝操作
    	//up2 = up1;		        // 错误,不可进行拷贝操作
    	unique_ptr<int> up4(new int(1025));
    	up4.reset(up2.release());
    	cout << "up4: " << *up4 << endl;
    
    	//Test Two
    	//上述对于拷贝的限制,有两个特殊情况,
    	//即unique_ptr可以作为函数的返回值和参数使用,这时虽然也有隐含的拷贝存在,但是并非不可行的。
    	cout << "test unique_ptr parameter and return value:" << endl;
    	auto up5 = CloneFunction(1024);
    	cout << "up5: " << *up5 << endl;
    	process_unique_ptr(move(up5));
    	//cout<<"up5 after process: "<<*up5<<endl; //错误segmentfault
    }
    

      

    0x05  weak_ptr

         weak_ptr一般和shared_ptr配合使用。它可以指向shared_ptr所指向的对象,但是却不增加对象的引用计数。这样就有可能出现weak_ptr所指向的对象实际上已经被释放了的情况。因此,weak_ptr有一个lock函数,尝试取回一个指向对象的shared_ptr。

         

    void Weak_PtrTest()
    {
    	//weak_ptr一般和shared_ptr配合使用。
    	//它可以指向shared_ptr所指向的对象,但是却不增加对象的引用计数。
    	//这样就有可能出现weak_ptr所指向的对象实际上已经被释放了的情况。因此,weak_ptr有一个lock函数,尝试取回一个指向对象的shared_ptr。
    	cout << "test weak_ptr basic usage:" << endl;
    	auto p10 = make_shared<int>(1024);
    	weak_ptr<int> wp1(p10);
    	assert(p10.use_count() == 1);
    	cout << "p10 use_count: " << p10.use_count() << endl;
    	//p10.reset(new int(1025)); // this will cause wp1.lock() return a false obj
    	shared_ptr<int> p11 = wp1.lock();
    	assert(p11.use_count() == 2);
    	if (p11) cout << "wp1: " << *p11 << " use count: " << p11.use_count() << endl;
    }
    

      

    0x06   小结

      shared_ptr采用引用计数的方式管理所指向的对象。shared_ptr可以使用一个new表达式返回的指针进行初始化;但是,不能将一个new表达式返回的指针赋值给shared_ptr。

    一旦将一个new表达式返回的指针交由shared_ptr管理之后,就不要再通过普通指针访问这块内存;shared_ptr可以通过reset方法重置指向另一个对象,此时原对象的引用计数减一。

      unique_ptr对于所指向的对象,是独占的;不可以对unique_ptr进行拷贝、赋值等操作,但是可以通过release函数在unique_ptr之间转移控制权;unique_ptr可以作为函数的返回值和参数使用。

      weak_ptr一般和shared_ptr配合使用;它可以指向shared_ptr所指向的对象,但是却不增加对象的引用计数;weak_ptr有一个lock函数,尝试取回一个指向对象的shared_ptr。

    完整源码:

    // 智能指针.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <Windows.h>
    #include <string>
    #include <iostream>
    #include<memory> 
    #include<assert.h>
    using namespace std;
    void Shared_PtrTest();
    void Unique_PtrTest();
    void Weak_PtrTest();
    
    int main()
    {
    	//Shared_PtrTest();
    	//Unique_PtrTest();
    	Weak_PtrTest();
    }
    
    void process(shared_ptr<int> ptr)
    {
    	cout << "in process use_count:" << ptr.use_count() << endl;
    }
    
    void Shared_PtrTest()
    {
    		//shared_ptr Test
    	//Test One
    	cout << "test shared_ptr base usage:" << endl;
    	shared_ptr<string> v1 = make_shared<string>("");
    	if (v1 && v1->empty())
    		*v1 = "Chronic";
    
    	auto v2 = make_shared<string>("LSH");
    	cout << *v1 << ' ' << *v2 << endl;
    
    	cout << "test shared_ptr use_count:" << endl;
    	cout << "v1 ReferenceCount:" << v1.use_count() << "	v2 ReferenceCount:" << v2.use_count() << endl;
    
    	auto v3 = v2;
    	cout << "v1 ReferenceCount:" << v1.use_count() << "	v2 ReferenceCount:" << v2.use_count() << "	v3 ReferenceCount:" << v3.use_count() << endl;
    	v2 = v1;
    	cout << "v1 ReferenceCount:" << v1.use_count() << "	v2 ReferenceCount:" << v2.use_count() << "	v3 ReferenceCount:" << v3.use_count() << endl;
    
    	//Test Two
    	//使用一个new表达式返回的指针进行初始化。
    	cout << "test shared_ptr and new:" << endl;
    	shared_ptr<int> p4(new int(1024));
    	//shared_ptr<int> p5 = new int(1024); // 错误
    	cout << *p4 << endl;
    
    	//Test Three
    	//不可混用new和shared_ptr!
    	cout << "不可混用new和shared_ptr!" << endl;
    	shared_ptr<int> p5(new int(1024));
    	process(p5);
    	int v5 = *p5;
    	cout << "v5: " << v5 << endl;
    
    	int *p6 = new int(1024);
    	//shared_ptr<int> p6(new int(1024));  正确做法
    	process(shared_ptr<int>(p6));
    	int v6 = *p6;
    	cout << "v6: " << v6 << endl;
    	/*
    	输出结果:
    	不可混用new和shared_ptr!
    	in process use_count:2
    	v5: 1024
    	in process use_count:1
    	v6: -572662307
    	*/
    
    	//Test Four
    	//shared_ptr可以通过reset方法重置指向另一个对象,此时原对象的引用计数减一。
    	//shared_ptr<string> v1 = make_shared<string>("LSH");
    	cout << "test shared_ptr reset:" << endl;
    	cout << "p1 cnt:" << v1.use_count() << endl;
    	v1.reset(new string("LSH Reset"));
    	cout << "p1 cnt:" << v1.use_count() << endl;
    }
    
    
    unique_ptr<int> CloneFunction(int p)
    {
    	return unique_ptr<int>(new int(p));
    }
    
    void process_unique_ptr(unique_ptr<int> up)
    {
    	cout << "process unique ptr: " << *up << endl;
    }
    
    void Unique_PtrTest()
    {
    	//Test One
    	//unique_ptr对于所指向的对象,正如其名字所示,是 独占 的。
    	//所以,不可以对unique_ptr进行拷贝、赋值等操作,但是可以通过release函数在unique_ptr之间转移控制权。
    	cout << "test unique_ptr base usage:" << endl;
    	unique_ptr<int> up1(new int(1024));
    	cout << "up1: " << *up1 << endl;
    	unique_ptr<int> up2(up1.release());
    	cout << "up2: " << *up2 << endl;
    	//unique_ptr<int> up3(up1); // 错误,不可进行拷贝操作
    	//up2 = up1;		        // 错误,不可进行拷贝操作
    	unique_ptr<int> up4(new int(1025));
    	up4.reset(up2.release());
    	cout << "up4: " << *up4 << endl;
    
    	//Test Two
    	//上述对于拷贝的限制,有两个特殊情况,
    	//即unique_ptr可以作为函数的返回值和参数使用,这时虽然也有隐含的拷贝存在,但是并非不可行的。
    	cout << "test unique_ptr parameter and return value:" << endl;
    	auto up5 = CloneFunction(1024);
    	cout << "up5: " << *up5 << endl;
    	process_unique_ptr(move(up5));
    	//cout<<"up5 after process: "<<*up5<<endl; //错误segmentfault
    }
    
    
    void Weak_PtrTest()
    {
    	//weak_ptr一般和shared_ptr配合使用。
    	//它可以指向shared_ptr所指向的对象,但是却不增加对象的引用计数。
    	//这样就有可能出现weak_ptr所指向的对象实际上已经被释放了的情况。因此,weak_ptr有一个lock函数,尝试取回一个指向对象的shared_ptr。
    	cout << "test weak_ptr basic usage:" << endl;
    	auto p10 = make_shared<int>(1024);
    	weak_ptr<int> wp1(p10);
    	assert(p10.use_count() == 1);
    	cout << "p10 use_count: " << p10.use_count() << endl;
    	//p10.reset(new int(1025)); // this will cause wp1.lock() return a false obj
    	shared_ptr<int> p11 = wp1.lock();
    	assert(p11.use_count() == 2);
    	if (p11) cout << "wp1: " << *p11 << " use count: " << p11.use_count() << endl;
    }
    

      

  • 相关阅读:
    HSL制作配色表
    css3 text-overflow制作固定区域的博客列表
    git 安装
    mailto: HTML e-mail 链接
    Sublime Text2 新建文件快速生成Html头部信息和炫酷的代码补全
    Git教程
    javscript 一些常用的工具方法
    LINQ to Entities 不识别方法"System.String ToString()",因此该方法无法转换为存储表达式 的解决方法
    Dictionary and KeyValuePair关系
    C# 类动态添加属性、方法
  • 原文地址:https://www.cnblogs.com/lsh123/p/8036959.html
Copyright © 2011-2022 走看看