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语言实现学生成绩管理系统项目

    C语言实现学生成绩管理系统项目攻略 1. 需求分析 在开发学生成绩管理系统前,我们需要对系统的功能需求进行分析。在此项目中,我们需要实现以下功能: 添加学生信息 删除学生信息 修改学生信息 查询学生信息 展示所有学生信息 2. 数据结构设计 在此项目中,我们需要定义一个结构体来存储学生的信息,该结构体包含以下信息: struct Student { int …

    C 2023年5月23日
    00
  • c++ For循环执行顺序流程图解

    下面是“c++ For循环执行顺序流程图解”的详细攻略。 什么是 For 循环? For循环是 C++ 中最常用的迭代结构之一。它可以用于循环任何可迭代的数据类型,例如整数、浮点数、数组或容器等。 For循环通常涉及以下三个部分: 初始化 (Initialization) —— 对循环变量进行初始化,通常是将其设置为零或某个初始值。 布尔表达式 (Boole…

    C 2023年5月23日
    00
  • C++第三方日志库Glog的安装与使用介绍

    下面是关于C++第三方日志库Glog的安装与使用介绍的完整攻略: 安装Glog 系统要求 安装Glog前,你需要拥有以下环境: 操作系统:Ubuntu/Debian或CentOS/RHEL 编译器:GCC 4.8或更高版本 步骤 下载安装依赖库 Glog依赖于很多库,需要先下载安装: Ubuntu/Debian: sudo apt-get install a…

    C 2023年5月23日
    00
  • ASP调用WebService转化成JSON数据,附json.min.asp

    ASP调用WebService转化成JSON数据,可以通过以下步骤完成: 创建一个WebService 在Visual Studio中创建一个WebService项目,添加一个Web服务方法,例如: [WebMethod] public string HelloWorld(string name) { return "Hello " + …

    C 2023年5月23日
    00
  • C语言实现扫雷小游戏的示例代码

    C语言是一门广泛应用于计算机编程领域的编程语言,扫雷小游戏是一款经典的益智小游戏,下面将详细讲解如何使用C语言实现扫雷小游戏的示例代码的完整攻略。 设计游戏界面 在开始编写扫雷小游戏的代码之前,我们先需要设计游戏界面。游戏板块一般是一个二维矩阵,可以通过字符来表示不同单元是否有雷。我们可以借助C语言中的二维字符数组来实现这一点。下面是一个游戏板块的初始界面代…

    C 2023年5月24日
    00
  • c++11 atomic的使用详解

    下面是关于”C++11 atomic的使用详解”的完整攻略。 什么是atomic atomic是一个C++11标准中的类模板,可用于实现原子操作。原子操作是一种不可分割的操作,要么成功执行,要么不执行,不会被其他线程中断。使用atomic可以确保并发访问下的线程安全。 基础用法 atomic支持内部类型如int、long等的原子操作。下面是一些基本的示例: …

    C 2023年5月22日
    00
  • Android SQLite详解及示例代码

    Android SQLite详解及示例代码 什么是Android SQLite SQLite是一个轻型的数据库库,它存储在设备的内部存储上,并提供了一些SQL接口用于读写数据。在Android开发中,SQLite是非常重要的一部分,它被广泛应用于Android应用的本地数据存储。 如何使用Android SQLite 1. 创建一个SQLite数据库 第一步…

    C 2023年5月23日
    00
  • C++实现统计代码运行时间计时器的简单实例

    下面就来详细讲解如何使用C++实现统计代码运行时间计时器的简单实例。 步骤一:引入头文件 在C++中,我们可以使用chrono标准库来实现计时器。在使用前,需要先引入头文件。在程序的开头,添加以下代码: #include <chrono> 步骤二:定义变量 接下来,我们需要定义两个time_point类型的变量,分别代表计时器的起始时间和结束时间…

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