[C++] 智能指针(shared_ptr、unique_ptr)

简介: [C++] 智能指针(shared_ptr、unique_ptr)

📢前言

      智能指针是行为类似于指针的类对象,单这种对象还有其他功能。本文介绍三个可帮助管理动态内存分配的智能指针类。先来看看需要哪些功能以及这些功能是如何实现的。请看下面的函数:

void remodel(std::string & str)
{
    std::string * ps = new std::string(str);
    ...
    str = ps;
    return;
}

      您可能发现了其中的缺陷。每当调用时,该函数都分配堆中的内存,单从不回收,从而导致内存泄漏。您可能也知道解决之道——只要别忘了在return语句前添加下面的语句,以释放分配的内存即可:

delete ps;

      然而,但凡涉及“别忘了”的解决方法,很少是最佳的。因为您有时可能忘了,有时可能记住了,但可能在不经意间深处或注释掉了这些代码。即使确实没有忘记,也可能有问题。请看下面的变体:

void remodel(std::string & str)
{
    std::string * ps = new std::string(str);
    ...
    if (weird_thing())
        throw exception();
    str = *ps;
    delete ps;
    return;
}

      当出现异常时,delete将不被执行,因此也将导致内存泄漏。

      如果ps有一个析构函数,该析构函数将在ps过期时释放它指向的内存,那么问题就解决了。因此,ps的问题在于,它只是一个常规指针,不是有析构函数的类对象。如果它是对象,则可以在对象过期时,让它的析构函数删除指向的内存。这正式auto_ptr、unique_ptr和shared_ptr背后的思想。模板shared_ptr允许多个指针指向同一个对象unique_ptr独占一个对象。定义在meory头文件中模板auto_ptr是C++98提供的解决方案,C++11已将其摒弃。然而,虽然auto_ptr被摒弃,单它已经使用了多年;同时,如果您的编译器不支持其他两中解决方法,auto_ptr将是唯一的选择方案。

总结:为什么使用智能指针?

      new申请动态内存,delete释放动态内存,注意有new必须要有相应的delete删除内存,不然会产生内存泄漏问题。为了解决这种内存泄漏问题,标准库包含两种智能指针(unique_ptr和shared_ptr),其可以自动释放内存。


✨动态内存与智能指针

      这三个只能指针模板(auto_ptr/unique_ptr和shared_ptr)都定义了类似指针的对象,可以将new或make_shared获得(直接或间接)的地址赋给这种对像。当只能指针过期时,其析构函数将使用delete来释放内存。因此,如果将new或make_shared返回的地址赋给这些对像,将无需记住稍候释放这些内存:在智能指针过期时,这些内存将自动被释放。

💫智能指针—shared_ptr

定义shared_ptr,定义和其它的模板类似,需要使用<>,默认初始化时会产生空指针。

shared_ptr<int>p1;        //p1为指针,指向string类型
shared_ptr<vector<int>>p2;//p2为指针,指向int的vector

一、分配和使用动态内存的方法:

1)使用new返回地址

std::shared_ptr<Test> p(new Test);

      很显然这段代码会引起一个内存分配,但实际上是有两次内存分配。条款19解释了每个std::shared_ptr会指向一个控制块,这个控制块除了其他一些东西,包含了所指对象的引用计数。控制块的内存分配是在std::shared_ptr的构造函数中进行的。这样直接用new需要为Widget来分配一次内存,还要为控制块再分配一次内存。

2)使用std::make_shared来代替new返回地址

std::shared_ptr<Test> p = std::make_shared<Test>();

      这样一次内存分配就足够了。那是因为std::make_shared会分配一块独立的内存既保存Widget对象又保存控制块。 这个优化减小了程序的静态尺寸,因为代码只包含一次内存分配的调用,同时增加了代码执行速度,因为只有一次内存分配。

总结:make_shared要优于使用new,make_shared可以一次将需要内存分配好,返回一个shared_ptr指针。在memory中定义,是最安全的分配和使用动态内存的方法。

注:要创建智能指针对象,必须包含头文件memory,该文件模板定义。然后使用通常的模板语法来实例化所需类型的指针。

此外,智能指针有一个get函数,可以得到shared_ptr指向对象的内置指针

std::shared_ptr<int>p(new int(2));
int *q=p.get();//q为一个内置指针,指向和p同一个对象,注意不要delete q

💥智能指针—unique_ptr

和shared_ptr不同,unique_ptr拥有它所有的唯一对象,这样就保证unique_ptr被销毁时,其对象也会被销毁。

只能使用new进行直接初始化,不支持普通拷贝和赋值。

std::unique_ptr<int>p1(std::make_shared<int>(2));//直接初始化
std::unique_ptr<int>p2;
p2=p1;//错误,不能同时指向一个对象

但可以所有权转移,使用reset或release。

unique_ptr<int>p1(new int(2));
unique_ptr<int>p2(p1.release());//release会将p1置为空,就是切断p1和它对象的联系
unique_ptr<int>p3(new int(1));
p2.reset(p3.release());//将p3置空并转权给p2;

 


戳戳小手帮忙点个免费的赞和关注吧,嘿嘿。

其他相关描述:C++智能指针shared_ptr、unique_ptr以及weak_ptr

目录
相关文章
|
12天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
35 4
|
28天前
|
存储 安全 编译器
在 C++中,引用和指针的区别
在C++中,引用和指针都是用于间接访问对象的工具,但它们有显著区别。引用是对象的别名,必须在定义时初始化且不可重新绑定;指针是一个变量,可以指向不同对象,也可为空。引用更安全,指针更灵活。
|
1月前
|
存储 C++
c++的指针完整教程
本文提供了一个全面的C++指针教程,包括指针的声明与初始化、访问指针指向的值、指针运算、指针与函数的关系、动态内存分配,以及不同类型指针(如一级指针、二级指针、整型指针、字符指针、数组指针、函数指针、成员指针、void指针)的介绍,还提到了不同位数机器上指针大小的差异。
38 1
|
1月前
|
存储 编译器 C语言
C++入门2——类与对象1(类的定义和this指针)
C++入门2——类与对象1(类的定义和this指针)
30 2
|
1月前
|
存储 安全 编译器
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(一)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
1月前
|
存储 C++ 索引
C++函数指针详解
【10月更文挑战第3天】本文介绍了C++中的函数指针概念、定义与应用。函数指针是一种指向函数的特殊指针,其类型取决于函数的返回值与参数类型。定义函数指针需指定返回类型和参数列表,如 `int (*funcPtr)(int, int);`。通过赋值函数名给指针,即可调用该函数,支持两种调用格式:`(*funcPtr)(参数)` 和 `funcPtr(参数)`。函数指针还可作为参数传递给其他函数,增强程序灵活性。此外,也可创建函数指针数组,存储多个函数指针。
|
2月前
|
编译器 C++
【C++核心】指针和引用案例详解
这篇文章详细讲解了C++中指针和引用的概念、使用场景和操作技巧,包括指针的定义、指针与数组、指针与函数的关系,以及引用的基本使用、注意事项和作为函数参数和返回值的用法。
41 3
|
1月前
|
存储 编译器 程序员
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值(二)
【C++】C++特性揭秘:引用与内联函数 | auto关键字与for循环 | 指针空值
|
2月前
|
安全 C++ 开发者
C++ 11新特性之shared_ptr
C++ 11新特性之shared_ptr
22 0
|
2月前
|
C++
C++(十八)Smart Pointer 智能指针简介
智能指针是C++中用于管理动态分配内存的一种机制,通过自动释放不再使用的内存来防止内存泄漏。`auto_ptr`是早期的一种实现,但已被`shared_ptr`和`weak_ptr`取代。这些智能指针基于RAII(Resource Acquisition Is Initialization)原则,即资源获取即初始化。RAII确保对象在其生命周期结束时自动释放资源。通过重载`*`和`-&gt;`运算符,可以方便地访问和操作智能指针所指向的对象。