STATUS: NOMINAL LOCAL TIME: 00:00:00 返回园内

[C++]智能指针

[C++]智能指针

智能指针是行为类似指针的类对象,析构时会释放指向的内存
C++98提供了auto_ptr,已被废弃;C++11提供了shared_ptr和unique_ptr以及weak_ptr。
所有智能指针类都有explicit构造函数,参数为指针。

抛弃auto_ptr转用unique_ptr的原因

参考下面一段代码:

std::auto_ptr< std::string > ap1(new std::string("Hello World\n"));
std::auto_ptr< std::string > ap2;
ap2 = ap1;

std::cout << *ap2;
std::cout << *ap1;

如果ap1和ap2都是普通指针,程序会试图删除同一个对象两次,也就是double free。

要避免这种问题,方法有多种:

  1. 定义赋值运算符,使之执行深复制。这样两个指针将指向不同的对象,其中的一个对象是另一个对象的副本。
  2. 建立所有权(ownership)概念,对于特定的对象,只能有一个智能指针可拥有它,这样只有拥有对象的智能指针的构造函数会删除该对象。然后让赋值操作转让所有权。这就是用于 auto_ptr
    和unique_ptr的策略,但unique_ptr的策略更严格。
  3. 创建智能更高的指针,跟踪引用特定对象的智能指针数。这称为引用计数(reference counting)。例如,赋值时,计数将加1,而指针过期时,计数将减1。仅当最后一个指针过期时,才调用delete。这是shared_ptr采用的策略。

所以以上代码执行结果只输出了一次“Hello World”,因为ap2剥夺了ap1的所有权,这似乎没毛病,但是程序是能编译运行的,编译器没有对访问ap1的行为作出检查。
将auto_ptr替换为unique_ptr:

std::unique_ptr< std::string > up1(new std::string("Hello World\n"));
std::unique_ptr< std::string > up2;
up2 = up1; // error here

赋值语句报错,因为up1仍然有可能被访问。但是如果赋值过后,up1不可能再被访问,那么编译器将运行这次赋值,比如将一个临时的右值赋给unique_ptr:

std::unique_ptr< std::string > up3;
up3 = std::unique_ptr< std::string >(new std::string("Hello World\n"));
// allowed

说到右值,不免想起移动语义std::move,是否可以将左值unique_ptr转换成右值再赋值呢?确实可以:

std::unique_ptr< std::string > up4;
up4 = std::move(up3); // allowed

unique_ptr优于auto_ptr的另一个点是,它支持数组的new[]与delete[]

shared_ptr和weak_ptr

shared_ptr的特点从它的名字就可以看出来,允许多个指针共享相同的资源。前文提到,这是通过引用计数来实习的,而shared_ptr类也提供了函数use_count来获取参与共享的所有指针数量。

std::shared_ptr< std::string > sp1(new std::string("Hello World\n"));
std::shared_ptr< std::string > sp2 = sp1;
std::cout << *sp1 << sp1.use_count(); // 2

weak_ptr主要用于解决shared_ptr相互引用时产生死锁的问题。它不控制所指向对象的生命周期。简单来说,它像一个“观察者”,可以访问 shared_ptr 管理的资源,但不会增加引用计数。
因此,weak_ptr不支持*->操作,而是调用lock()函数,获取shared_ptr对象来访问数据。而shared_ptr也可以直接赋值给weak_ptr。

为什么要用智能指针

自动内存管理,杜绝泄漏;避免重复释放和悬挂指针
明确所有权语义:
unique_ptr:独占所有权,不可拷贝只可移动
shared_ptr:共享所有权,引用计数管理
weak_ptr:弱引用,观察但不拥有

posted @ 2026-03-22 16:37  猫爹爱猫娘  阅读(15)  评论(0)    收藏  举报