c++11 新特性——智能指针使用详解

C++11 新特性——智能指针使用详解

在C++中,内存管理一直是一个非常重要的事情,一个常见的错误就是忘记释放先前分配的内存。C++11引入了智能指针,从而使得内存管理更加方便。本文将详细介绍智能指针的使用方法。

智能指针概述

C++中的智能指针是一种RAII(Resource Acquisition Is Initialization)机制的实现,它通过对象生命周期的结束来自动释放分配的内存。

在C++11中,常见的智能指针有两种:std::unique_ptr和std::shared_ptr。下面将分别详细说明它们的用法。

std::unique_ptr

std::unique_ptr是一种独占所有权的智能指针。它保证同时只有一个指针可以指向被分配的内存,并且在它被销毁时会自动释放这个内存,即可以避免内存泄漏。

unique_ptr的定义和初始化

std::unique_ptr的定义样式如下:

std::unique_ptr<type> ptr_name(new type(args));

其中,type为要分配内存的类型,ptr_name为指向该类型对象的智能指针,new type(args)用于分配堆内存并返回该堆内存的地址。

下面是一个示例:

std::unique_ptr<int> p(new int(10));

这个语句创建了一个指向int类型对象的智能指针p,并将值为10的整数存放在指针指向的内存位置。

unique_ptr的拷贝和移动

由于std::unique_ptr是独占所有权的,因此它不能被其他指针指向。但是,我们可以使用std::move函数将其转移给另一个unique_ptr。如下所示:

std::unique_ptr<int> p1(new int(10));
std::unique_ptr<int> p2(std::move(p1));

这个语句创建了两个指向int类型对象的智能指针p1和p2,其中p2是通过std::move函数从p1转移而来的。

值得注意的是,由于唯一所有权,std::unique_ptr是不能被拷贝的。以下代码会导致编译错误:

std::unique_ptr<int> p1(new int(10));
std::unique_ptr<int> p2(p1); // 编译错误

unique_ptr的使用

std::unique_ptr的使用方法与普通指针类似,可以使用*或->操作符来访问其所指向的对象,如下所示:

std::unique_ptr<int> p(new int(10));
std::cout << *p << std::endl;

这个语句输出p指向的int类型对象的值,即10。

除此之外,std::unique_ptr还提供了release函数和reset函数。

release函数用于将std::unique_ptr中的指针地址返回并释放所有权。下面是一个示例:

std::unique_ptr<int> p(new int(10));
int* ptr = p.release();

这个语句将p中的指针地址释放,并将其返回给变量ptr。

reset函数用于释放当前指向的对象,并将指针指向新对象。下面是一个示例:

std::unique_ptr<int> p(new int(10));
p.reset(new int(20));
std::cout << *p << std::endl;

这个语句释放p指向的int类型对象,并将p指向一个新的地址,该地址存放了值为20的整数。

std::shared_ptr

std::shared_ptr是一种共享所有权的智能指针。它可以使多个指针指向同一块内存,并可以在最后一个指针被销毁时自动释放该内存,避免了内存泄露。

shared_ptr的定义和初始化

std::shared_ptr的定义样式如下:

std::shared_ptr<type> ptr_name(new type(args));

其中,type为要分配内存的类型,ptr_name为指向该类型对象的智能指针,new type(args)用于分配堆内存并返回该堆内存的地址。

下面是一个示例:

std::shared_ptr<int> p1(new int(10));
std::shared_ptr<int> p2 = p1; // p2和p1共享所有权

这个语句创建了两个指向int类型对象的智能指针p1和p2,其中p2是从p1拷贝而来的。由于std::shared_ptr是共享所有权的,因此p1和p2指向同一个int类型对象,并且在这两个指针被销毁时,它们会自动释放该内存。

shared_ptr的使用

std::shared_ptr的使用方法与普通指针类似,可以使用*或->操作符来访问其所指向的对象,如下所示:

std::shared_ptr<int> p(new int(10));
std::cout << *p << std::endl;

这个语句输出p指向的int类型对象的值,即10。

除此之外,std::shared_ptr还提供了一个use_count函数,用于返回当前有多少个智能指针指向该对象。下面是一个示例:

std::shared_ptr<int> p1(new int(10));
std::shared_ptr<int> p2 = p1;
std::cout << "The use count is " << p1.use_count() << std::endl; // 输出2

这个语句输出指向int类型对象的智能指针的个数,即2。

示例

下面是一个使用std::unique_ptr的示例,用于分配包含两个字符串的结构。

struct test
{
    std::string str1;
    std::string str2;
    test() : str1(""), str2("") { }
    test(const std::string& s1, const std::string& s2) : str1(s1), str2(s2) { }
};

int main()
{
    std::unique_ptr<test> ptest(new test("Hello", "world"));
    std::cout << ptest->str1 << ", " << ptest->str2 << std::endl;

    return 0;
}

这段代码首先定义了一个结构体test,其包含两个string类型的成员变量str1和str2。然后,通过std::unique_ptr分配一个test类型的对象,其中使用了结构体构造函数初始化了它的两个成员变量。最后,通过unique_ptr的->操作符访问了该结构体的成员变量,并将它们输出到终端上。

下面是一个使用std::shared_ptr的示例,用于模拟对象间的引用:

#include <iostream>
#include <memory>

class test;

void func(std::shared_ptr<test> p);

class test
{
public:
    test() { std::cout << "test is constructed" << std::endl; }
    ~test() { std::cout << "test is destructed" << std::endl; }
    void func(std::shared_ptr<test> p)
    {
        std::cout << "test's func is called" << std::endl;
    }
};

void func(std::shared_ptr<test> p)
{
    std::cout << "func is called" << std::endl;
    p->func(p);
}

int main()
{
    std::shared_ptr<test> p1(new test());
    func(p1);

    return 0;
}

这个代码模拟了两个对象,它们之间相互引用。该示例中,通过std::shared_ptr分配了一个test类型的对象,并将其传递给func函数。在func函数中,使用std::shared_ptr调用了test类的成员函数func,并将该智能指针作为参数传递给了该函数。

在这个示例中,由于使用了std::shared_ptr,因此两个对象之间的引用始终保持着,并且在所有引用被销毁时,它们指向的内存会被自动释放,从而避免了内存泄漏。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:c++11 新特性——智能指针使用详解 - Python技术站

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

相关文章

  • 如何利用C++实现mysql数据库的连接池详解

    如何利用C++实现mysql数据库的连接池详解 什么是数据库连接池 数据库连接池是一种用来缓存数据库连接的技术,它可以提高数据库的访问效率,避免重复连接数据库导致的资源浪费和性能下降。在高并发的情况下,数据库连接池会发挥更大的优势。 如何利用C++实现mysql数据库的连接池 1. 安装mysql C++ Connector mysql C++ Connec…

    C 2023年5月22日
    00
  • C语言实现简易的三子棋游戏

    C语言实现简易的三子棋游戏攻略 游戏规则 三子棋是一种比较简单的棋类游戏,其规则如下: 游戏由两个玩家进行,每个玩家分别使用”X”或”O”代表自己的棋子。 游戏在一个3×3的游戏棋盘上进行,玩家轮流在未被占用的方格中放置自己的棋子。 第一个将自己的三个棋子连成一条线的玩家获胜。 如果游戏棋盘填满了,但是没有任何一方获胜,则游戏以平局结束。 程序设计 这里我们…

    C 2023年5月23日
    00
  • C 语言基础教程(我的C之旅开始了)[七]

    针对“C 语言基础教程(我的C之旅开始了)[七]”这篇文章,我将为您进行详细讲解。 概述 文章主要讲解 C 语言中的数组。内容涉及数组的定义、初始化、访问以及数组名的特性等方面。 数组的定义 在 C 语言中,数组是一组类型相同的元素所组成的集合。我们可以通过声明一个数组来定义一个由多个元素构成的数组。 数组的一般定义形式为 type arrayName[ar…

    C 2023年5月23日
    00
  • 图文精讲java常见分布式事务理论与解决方案

    图文精讲Java常见分布式事务理论与解决方案 一、分布式事务概念 分布式事务指多个数据库或者多个应用之间的数据一致性问题。 例如,当一个事务需要涉及到多个数据库,并且这些数据库都需要成功地提交,才能使整个事务得以完成,此时就需要进行分布式事务的处理。 二、分布式事务的问题 在分布式环境下操作数据时,常常会出现下列问题: 并发问题:多个节点同时访问相同的数据;…

    C 2023年5月22日
    00
  • C++ 实现LRU 与 LFU 的缓存算法

    C++ 实现LRU 与 LFU 的缓存算法 算法描述 LRU和LFU是常用的缓存算法。它们能够优化系统读写速度,提高系统效率。 LRU LRU (Least Recent Used)是最近最少使用算法,维护一个缓存队列,每次访问缓存中的一个元素时,将其移动到队列的头部,当缓存队列满时删除队尾元素,保证最近使用过的元素在缓存队列的最前面,最近没有使用过的元素在…

    C 2023年5月22日
    00
  • Android编程之json解析实例详解

    我将为你介绍一下 “Android编程之json解析实例详解” 的完整攻略。 1. 什么是Json? JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它基于JavaScript代码语法,但是与之无关。在Android编程中,Json数据常常被用来传递数据。 2. Json的基本格式 下面是一个Json的基本格式: …

    C 2023年5月23日
    00
  • mysql 如何使用JSON_EXTRACT() 取json值

    当mysql存储JSON格式的数据时,我们需要对JSON进行提取。MySQL 5.7版本以上,提供了JSON_EXTRACT()函数来实现从JSON中提取值。 JSON_EXTRACT()函数的语法 JSON_EXTRACT(json_path) json_path为JSON路径参数,返回该路径下的JSON值。 示例1 已知json字段’data’的值为: …

    C 2023年5月23日
    00
  • Windows10配置VSCode C++环境(超详细,面向小白以及大佬们)

    Windows10配置VSCode C++环境(超详细,面向小白以及大佬们) 1. 安装Visual Studio Code 首先需要安装Visual Studio Code(VSCode),可以到官网 https://code.visualstudio.com/ 下载安装包进行安装。安装完成后打开VSCode,点击左侧扩展图标,搜索”Code Runner…

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