C++ share_ptr智能指针使用详解

C++ share_ptr智能指针使用详解,第1张

概述share_ptr 智能指针 ,也被称为 共享指针 ,用于管理可以由多个智能指针共同拥有的动态分配对象。特别是,类型 shared_ptrT 用于管理 T 类型对象的所有权。 类构造函数 shared_ptrT(T * ptr) share_ptr 智能指针,也被称为共享指针,用于管理可以由多个智能指针共同拥有的动态分配对象。特别是,类型 shared_ptr<T> 用于管理 T 类型对象的所有权。

类构造函数 shared_ptr<T>(T * ptr) 可用于创建共享指针,管理由裸指针 ptr 给定地址的对象。shared_ptr 类可以重载指针运算符 *->。以下示例创建了一个由共享指针管理的动态分配整数,然后即可通过该指针访问它:
int main(){    shared_ptr<int> p(new int);    *p = 45;    cout << *p + 1;    return 0;}
该代码将打印值 46。

以下是另外一个示例。假设要管理以下类对象的共享所有权:
class Person{    string name;    int age;       public:        string to_string()        {            return name + "" + to_string(age) + "\n";        }        //构造函数        Person () { name = " ";age = 0;}        Person(const strings name,int age)        {            this->name = name;            this->age = age;        }}
现在可以创建 2 个共享指针,每一个都可以管理不同的对象,就像下面这样;

shared_ptr<Person> p1(new Person());
shared_ptr<Person> p2 (new Person ("Maria Wu",23));

或者,也可以写成以下形式:

shared_ptr<Person> p1 = shared_ptr<Person>(new Person ());
shared_ptr<Person> p2 = shared_ptr<Person>(new Person("Maria Wu",23));

share_ptr组假设已经设置了一个共享指针来管理由裸指针 rPtr 指向的对象:

T * rPtr = new T();
shared_ptr<T> sPtr1(rPtr);

此时,sPtr1 变成了一个拥有 rPtr 的共享指针组中的唯一成员。该组维护了一个引用计数,即属于该组的共享指针数量。这个"组"被称为控制块,它本身实际上就是动态分配对象,可以保持跟踪引用计数和指向被管理对象的裸指针。当引用计数降至 0 时,控制块负责删除被管理的对象。可以将共享指针视为指向控制块的指针,而将控制块视为指向被管理的对象。

现在,如果 sPtr1 被用于初始化其他的共享指针,如以下语句所示:

shared_ptr<T> sPtr2 = sPtr1;

则 sPtr2 将变成和 sPtr1 同组的成员,共享 rPtr 对象的所有权,并且该组的引用计数也会增加 1。如果在此之后,sPtr2 被赋给了其他共享指针的值:

sPtr2 = sPtr3;

则 sPtr2 将放弃 rPtr 的所有权,离开 sPtr1 的组,转而加入 sPtr3 的组。第一个组(sPtr1 所在的组)的引用计数将减去 1,而第二个组(sPtr3 所在的组)的引用计数则增加 1。
双重管理的危险在使用 share_ptr 时,应该避免出现可能导致两个指针组管理相同对象的情况。例如,来看以下代码:
T * rPtr = new T();shared_ptr<T> sPtr1(rPtr);shared_ptr<T> sPtr2(rPtr);
这两个共享指针指向两个不同的控制块,但控制块管理的却是相同的对象。如果第一个组的引用计数降至 0 并删除该对象,那么这将导致其他组的指针变成悬挂指针。为了避免出现这种问题,给定的裸指针应该最多只能初始化一个共享指针。
make_shared<T>()函数再来看一下 share_ptr 创建语句:

shared_ptr<Person> p1(new Person());

该语句的执行涉及两个独立的内存分配:一个分配控制块,第二个则分配内存给被管理的 Person 对象。每个内存分配都会产生相当一部分开销,所以,更高效的做法是,分配一个足够大的内存块,以同时保存控制块和被管理的对象。

下面这个库函数就可以做到这一点:

make_shared<T>()

使用该函数即可将上述共享指针创建语句改写为以下形式:

shared_ptr<Person> p1 = make_shared<Person>();

该版本的 make_Shared 语句可以使用默认构造函数初始化被管理的对象。

还有一个版本的 make_shared 语句可以采用传递给非构造函数的形参。因此,以下面的语句为例:

shared_ptr<Person> p2 (new Person ("Maria Wu",23));

该语句可以被改写为以下形式:

shared_ptr<Person> p2 = make_shared<Person>("Maria Wu",23);

推荐使用 make_shared 函数方式创建共享指针。除了更高效之外,它还无须直接处理裸指针,因此也消除了双重管理的可能性。
shared_ptr 成员函数表 1 列出了处理 share_ptr 时最用的成员函数。

表 1 shared_ptr成员函数
成员函数描 述
T* get()返回指向被管理对象的裸指针,如果没有被管理的对象,则返回空指针
voID reset()释放任何可能存在的被管理对象的所有权。调用的共享指针被置为空
voID reset(T* ptr)释放当前被管理的对象的所有权。获取由 ptr 指向的对象的所有权
long use_count()返回引用相同的被管理对象的共享指针数量

除此之外,还可以通过测试共享指针的值,检查某个共享指针是否有被管理的对象, 示例如下:
shared_ptr<T> p =....;if ( P ){    //被管理的对象}else{    //共享指针为空}
指向数组的share_ptr默认情况下,shared_ptr 使用 delete 销毁被管理的对象。与 unique_ptr 不同的是,不能编写以下形式的语句:

shared_ptr<T[ ] > sPtr; // 错误

不能使用以上语句指定被管理的对象类型为数组。有一种简单方法可以绕过这种限制,那就是使用指向 T 类型矢量的共享指针:

shared_ptr<vector<T>> svecPtr;

当矢量被销毁时,其析构函数将运行并销毁所有的矢量元素。
总结

以上是内存溢出为你收集整理的C++ share_ptr智能指针使用详解全部内容,希望文章能够帮你解决C++ share_ptr智能指针使用详解所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

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

原文地址: http://outofmemory.cn/langs/1231181.html

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

发表评论

登录后才能评论

评论列表(0条)

保存