C++ 智能指针详解

本文详细介绍了C++11中的智能指针,包括shared_ptr、weak_ptr和unique_ptr的用法和特点。重点阐述了智能指针如何解决动态内存管理问题,以及在多线程和防止内存泄露中的角色。特别提到了shared_ptr的引用计数机制、拷贝赋值行为,以及weak_ptr在解决循环引用问题中的关键作用。
摘要由CSDN通过智能技术生成

C++ 智能指针详解

1. 智能指针能解决什么问题?

在C++中,动态内存的管理是通过一对运算符来完成的:

new,在动态内存中为对象分配空间并返回一个指向该对象的指针,可以选择对对象进行初始化;
delete,接受一个动态对象的指针,销毁该对象,并释放与之关联的内存。

动态内存的使用很容易出问题,因为确保在正确的时间释放内存是极其困难的。有时会忘记释放内存,在这种情况下会产生 内存泄露;有时在尚有指针引用内存的情况下就释放了它,在这种情况下就会产生引用非法内存的指针。

为了更容易(同时也更安全)地使用动态内存,C++11标准库提供智能指针(smart pointer)类型来管理动态对象。

智能指针的行为类似常规指针,重要的区别是它负责 自动释放所指的对象

智能指针是模板类而不是指针。类似vector,当创建一个智能指针时,必须提供额外的信息即指针可以指向的类型。默认初始化的智能指针中保存着一个空指针。智能指针的使用方式与普通指针类似。解引用一个智能指针返回它指向的对象。如果在一个条件判断中使用智能指针,效果就是检测它是否为空。

2. 智能指针的发展

1. auto_ptr (已被C++11舍弃)

最早的智能指针 auto_ptr 出现在 C++ 98 里面,目前已经被 C++11 标准舍弃

  • auto_ptr,对于拷贝构造和赋值运算符重载,该智能指针采用 管理权转移 的方式

当一个指针拷贝构造另一个指针时,当前指针就将对空间的管理权交给拷贝的那个指针,当前指针就指向空);

  • 但是这种方式不符合指针的要求(可以允许多个指针指向同一块空间,将一个指针赋值给另一个指针的时候,就是需要让两个指针指向同一块空间,而 auto_ptr只允许一块空间上只能有一个指针指向它),并且当管理权转移之后要想再访问之前的指针,就会出错,因为之前的指针已经为NULL,就会出现解引用空指针的问题。

2. Boost 的 scoped_ptr、shared_ptr、weak_ptr

因为 auto_ptr 有缺陷,但是 C++ 标准里面从 C++98 到 C++11 之间没有出现新的智能指针能解决这个缺陷,所以在这段时间内,boost 这个官方组织 就增加了智能指针(scoped_ptr,shared_ptr,weak_ptr等)

scoped_ptr 采用防拷贝的方式(防拷贝就是不允许拷贝,拷贝就会出错;防拷贝的实现:将拷贝构造和的赋值运算符重载只声明不实现,并且声明为私有)。

shared_ptr 为共享指针,里面采用引用计数,当有其他的 shared_ptr 指向同一块空间的时候就增加引用计数,当引用计数减为 0 的时候才释放该智能指针管理的那块空间。

weak_ptr 是位解决 shared_ptr 循环引用问题而出现的。

3. C++11 的 Unique_ptr、shared_ptr、Weak_ptr

C++11 在 Boost 库的基础上设计出三种新的智能指针。

C++11 里面的 unique_ptr 就是 boost 库里面的 scoped_ptr(防拷贝,独占);

C++11 的 shared_ptr 被广泛使用,在下面详细介绍。

3. 智能指针 shared_ptr

shared_ptr 是一个引用计数智能指针,用于共享对象的所有权,也就是说它允许多个指针指向同一个对象。这一点与原始指针一致。

对于shared_ptr在拷贝和赋值时的行为,《C++Primer第五版》中有详细的描述:

每个shared_ptr都有一个关联的计数值,通常称为引用计数。无论何时我们拷贝一个shared_ptr,计数器都会递增。

例如,当用一个 shared_ptr初始化另一个 shred_ptr,或将它当做参数传递给一个函数以及作为函数的返回值时,它所关联的计数器就会递增。当我们给 shared_ptr 赋予一个新值或是 shared_ptr 被销毁(例如一个局部的shared_ptr离开其作用域)时,计数器就会递减。一旦一个 shared_ptr 的计数器变为0,它就会自动释放自己所管理的对象。

3.1 创建shared_ptr实例

最安全和高效的方法是调用make_shared库函数, 该函数会在堆中分配一个对象并初始化,最后返回指向此对象的share_ptr实例。如果你不想使用make_ptr,也可以先明确new出一个对象,然后把其原始指针传递给share_ptr的构造函数。

int main() 
{
   

    // 传递给make_shared函数的参数必须和shared_ptr所指向类型的某个构造函数相匹配
    shared_ptr<string> pStr = make_shared<string>(10, 'a');
    cout << *pStr << endl;  //  aaaaaaaaaa

    int *p = new int(5);
    shared_ptr<int> pInt(p);
    cout << *pInt << endl;  // 5
}

3.2 访问所指对象

shared_ptr 的使用方式与普通指针的使用方式类似, 既可以使用解引用操作符 * 获得原始对象进而访问其各个成员,也可以使用指针访问符 -> 来访问原始对象的各个成员。

3.3 拷贝和赋值操作

我们可以用一个shared_ptr对象来初始化另一个share_ptr实例,该操作会增加其引用计数值


int main() 
{
   
    shared_ptr<string> pStr = make_shared<string>(10, 'a');
    cout << pStr.use_count() << endl;  //  1

    shared_ptr
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值