C++11 shared_ptr 与 make_shared源码剖析详解

C++11中的shared_ptr和make_shared是两个非常实用的特性,能够帮助我们更好地管理内存。本文将深入介绍shared_ptr和make_shared的实现原理,帮助读者更好地掌握这两个特性。

1. shared_ptr简介

shared_ptr是C++11提供的一种智能指针,用于管理动态内存。它可以自动对内存进行引用计数,并在引用计数为0时自动释放内存。shared_ptr使用起来非常方便,并且可以避免内存泄漏。

shared_ptr可以像原生指针一样进行赋值、比较和解引用,但它会自动进行引用计数。因此,多个shared_ptr对象可以指向同一个内存块,同时对它进行引用计数,当引用计数为0时自动释放内存。

2. make_shared简介

make_shared是C++11提供的一种智能指针构造函数,它可以更快速、更安全地构造shared_ptr对象。make_shared会在内存中分配一个新的对象,并且将这个对象封装在一个shared_ptr内部。这个新的对象会自动被初始化为默认值(或者按照提供的参数进行初始化)。

使用make_shared可以节省内存、提高效率,并且可以避免内存泄漏。

3. shared_ptr的实现原理

shared_ptr的实现原理比较复杂,主要包括内存管理、引用计数等。下面我们来详细介绍一下。

3.1 内存管理

当我们使用shared_ptr来管理一个指针时,它会在堆上分配一块内存来存储引用计数、指针等信息。同时,它也会在堆上分配一块内存来存储我们需要管理的对象。这两块内存会被绑定在一起,组成一个shared_ptr对象。

在这个过程中,我们需要注意内存泄露的问题。如果我们将一个原生指针赋值给一个shared_ptr对象时,这个原生指针所指向的内存块就不再由我们手动管理了。如果我们在后面的代码中使用这个原生指针,就有可能出现内存泄漏的情况。

3.2 引用计数

当我们使用shared_ptr来管理一个对象时,每个shared_ptr对象都会包含一个计数器,用于记录当前有多少个shared_ptr对象引用了这个对象。在shared_ptr对象的拷贝构造函数、拷贝赋值运算符、析构函数等操作中,都需要进行引用计数的操作。

当一个新的shared_ptr对象被创建时,它的计数为1。当它被拷贝构造时,它的计数会加1;当它被拷贝赋值时,它的计数会减1(可能会降至0,此时需要释放内存);当它被销毁时,它的计数会减1(可能会降至0,此时需要释放内存)。

3.3 循环引用问题

当两个shared_ptr对象相互引用时,就会出现循环引用的问题。这种情况下,两个shared_ptr对象的计数都不会降至0,因此它们所指向的内存块永远不会被释放。这就会导致内存泄漏的问题。

为了解决循环引用的问题,我们可以使用weak_ptr。weak_ptr也是一种智能指针,但它不会对对象进行引用计数。也就是说,当我们使用weak_ptr来引用对象时,它不会增加对象的引用计数。因此,当一个对象被多个shared_ptr对象引用时,我们可以使用weak_ptr来解决循环引用的问题。

4. make_shared的实现原理

make_shared的实现原理比shared_ptr更加复杂,但它也更加高效。下面我们来介绍一下make_shared的实现原理。

4.1 内存管理

make_shared会在内存中分配一个新的对象,并且将这个对象封装在一个shared_ptr内部。这个新的对象会自动被初始化为默认值(或者按照提供的参数进行初始化)。

为了实现这个功能,make_shared需要使用到C++11的可变参数模板。它可以将任意多个参数转化为一个变长的参数列表,然后将这个参数列表传递给一个模板类。

4.2 内存分配

在make_shared的实现中,我们需要进行内存分配并进行初始化操作。为了提高效率,我们可以将内存分配和初始化操作合并在一起,使用一个malloc函数来完成它们。

malloc函数是C++标准库中的一个函数,用于在堆上分配一块内存。使用malloc函数可以避免内存泄漏的问题,同时也可以提高效率。

4.3 构造shared_ptr对象

在make_shared的实现中,我们需要构造一个shared_ptr对象,并将它指向新分配的对象。这个过程涉及到shared_ptr的构造函数和虚函数表等内容。

当我们使用shared_ptr来管理一个对象时,它会在堆上分配一块内存来存储引用计数、指针等信息。同时,它也会在堆上分配一块内存来存储我们需要管理的对象。这两块内存会被绑定在一起,组成一个shared_ptr对象。

在make_shared的实现中,我们需要使用一个新分配的对象来替换旧的shared_ptr对象。为了完成这个操作,我们需要使用到C++11中的emplace函数。这个函数可以将一个元素加入到容器中,并用元素的构造函数进行初始化操作。

5. 示例说明

下面我们来介绍两个使用shared_ptr和make_shared的示例。这些示例可以帮助你更好地理解这两个特性。

5.1 shared_ptr示例

#include <memory>
#include <iostream>

class Foo {
public:
    void bar() { std::cout << "Hello, world!" << std::endl; }
};

int main() {
    std::shared_ptr<Foo> p1(new Foo);
    std::shared_ptr<Foo> p2 = p1;

    std::cout << p1.use_count() << std::endl;  // 输出2
    std::cout << p2.use_count() << std::endl;  // 输出2

    p1->bar();  // 输出Hello, world!
    p2->bar();  // 输出Hello, world!

    return 0;
}

在这个示例中,我们使用了shared_ptr来管理一个对象。我们创建了两个shared_ptr对象p1和p2,它们都指向同一个对象。当p1和p2被销毁时,它们会自动释放对内存的引用。

5.2 make_shared示例

#include <memory>
#include <iostream>

class Foo {
public:
    Foo() { std::cout << "Foo()" << std::endl; }
    Foo(int i) { std::cout << "Foo(" << i << ")" << std::endl; }
};

int main() {
    std::shared_ptr<Foo> p1(new Foo);
    std::shared_ptr<Foo> p2 = std::make_shared<Foo>();

    std::shared_ptr<Foo> p3 = std::make_shared<Foo>(42);

    return 0;
}

在这个示例中,我们使用了make_shared来构造一个对象。我们创建了三个shared_ptr对象p1、p2和p3,并使用了不同的方式来构造它们。当p1、p2和p3被销毁时,它们会自动释放对内存的引用。其中,p2和p3的构造方式更加高效。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++11 shared_ptr 与 make_shared源码剖析详解 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C 标准库 limits.h

    C 标准库 limits.h 提供了有关整数类型(如 int、long、long long 等)的限制值(上下界)的常量定义。下面是 limits.h 中提供的一些常量及其含义: CHAR_BIT:字符类型(char)的位数,在大部分系统中这个值都为 8。 SCHAR_MIN:有符号字符类型(signed char)的最小值。 SCHAR_MAX:有符号字符…

    C 2023年5月10日
    00
  • C++中volatile关键字及常见的误解总结

    C++中volatile关键字及常见的误解总结 什么是volatile关键字 volatile 是一个类型修饰符,用于告诉编译器,该变量可能在程序执行阶段被不由程序本身产生的修改。 通俗点讲,当我们定义一个变量时,系统会在内存中为其分配一块内存区域,我们通过对这些内存的读写来操作这些变量。但是在复杂的多线程并发编程中,可能出现另外一个线程或者硬件设备修改了这…

    C 2023年5月23日
    00
  • vscode中launch.json和task.json配置教程(重要参数详解)

    接下来我会详细讲解“vscode中launch.json和task.json配置教程(重要参数详解)”的完整攻略,分为以下几部分: 一、 launch.json 1.1 什么是launch.json launch.json是Visual Studio Code配置文件之一,用于设置VS Code的调试器。 1.2 如何创建launch.json文件 在打开的…

    C 2023年5月23日
    00
  • C语言类的基本语法详解

    C语言类的基本语法详解 概述 C语言是一门广泛使用的编程语言,具有较强的系统编程能力。本文将详细介绍C语言的基本语法。 变量 C语言中的变量由其类型和名称两部分组成。变量的类型定义变量能够保存的数据类型,常用的变量类型包括: int: 整数类型,占用4个字节 float: 单精度浮点数类型,占用4个字节 double: 双精度浮点数类型,占用8个字节 cha…

    C 2023年5月22日
    00
  • 一文弄懂MYSQL如何列转行

    一文弄懂MYSQL如何列转行 背景 在数据库中,有时候需要将列转换成行来展示数据。例如一个表中有多个日期字段,需要将每个日期字段的值作为新的行的一列来展示数据。 原理 MYSQL中提供了UNION ALL语句来实现列转行的功能。该语句可以将多个SELECT语句的结果合并成一个结果集。通过多个SELECT语句中的UNION ALL,可以将多行数据合并成一行,达…

    C 2023年5月22日
    00
  • C语言中的分支循环其嵌套语句

    C语言中的分支循环语句是控制程序流程的重要工具,它们可以根据条件来执行不同的代码块,或者循环执行某段代码块。与此同时,C语言还支持分支循环语句的嵌套,这种语句结构可以更精细地控制程序流程,提高代码的效率和可维护性。下面是完整的攻略。 分支语句 if语句 if语句是最基本的分支语句,用来测试一个条件,如果满足条件就执行指定的代码块。 语法: if (条件) {…

    C 2023年5月23日
    00
  • 电脑蓝屏代码0xc0000225怎么解决? 电脑0xc0000225错误的解决办法

    电脑蓝屏代码0xc0000225怎么解决 在使用电脑的过程中,可能会遇到蓝屏错误代码0xc0000225,导致电脑无法正常使用。本文将为您介绍该错误的原因,并提供解决该错误的相关方法。 错误原因 出现0xc0000225错误意味着启动程序无法正确加载winload.efi文件。通常情况下,这种问题可能是由以下原因引起的: 应用项损坏 启动数据损坏 硬件故障(…

    C 2023年5月23日
    00
  • windows蓝屏故障Stop:C0000135 Unknown Hard Error解决方法

    windows蓝屏故障Stop:C0000135 Unknown Hard Error解决方法 在使用 Windows 操作系统时,有时候会遇到蓝屏死机的情况,特别是在启动或进入 Windows 操作系统时。其中一种蓝屏死机错误是 “Stop:C0000135 Unknown Hard Error”,这是一个非常常见的错误类型,表示发生了未知的硬件错误。 诊…

    C 2023年5月24日
    00
合作推广
合作推广
分享本页
返回顶部