shared_ptr和动态数组

2024-06-12 00:48
文章标签 动态 数组 shared ptr

本文主要是介绍shared_ptr和动态数组,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

shared_ptr和动态数组

转载自 shared_ptr和动态数组


std::shared_ptr智能指针是c++11一个相当重要的特性,可以极大地将开发者从资源申请/释放的繁重劳动中解放出来。

然而直到c++17前std::shared_ptr都有一个严重的限制,那就是它并不支持动态数组:

#include <memory>std::shared_ptr<int[]> sp1(new int[10]()); // 错误,c++17前不能传递数组类型作为shared_ptr的模板参数
std::unique_ptr<int[]> up1(new int[10]()); // ok, unique_ptr对此做了特化std::shared_ptr<int> sp2(new int[10]()); // 错误,可以编译,但会产生未定义行为,请不要这么做

sp1错误的原因很明显,然而sp2的就没有那么好找了,究其原因,是因为std::shared_ptr对非数组类型都使用delete p释放资源,显然这对于new int[10]来说是不对的,对它应该使用delete [] p

其实c++17前的解决方案并不复杂,我们可以借助std::default_delete,它用于提供对应类型的正确的delete操作:

std::shared_ptr<int> sp3(new int[10](), std::default_delete<int[]>());

现在我们提供了正确的delete操作,可以放心地使用了。

不过这么做的缺点也是很明显的:

  1. 我们想管理的值是int[]类型的,然而事实上传给模板参数的是int
  2. 需要显示提供delete functor
  3. 不能使用std::make_shared,无法保证异常安全
  4. c++17前shared_ptr未提供opreator[],所以当需要类似操作时不得不使用sp3.get()[index]的形式

事实上共享一片连续分配内存的需求是极为常见的,所以为了修正上述缺陷,c++17以及即将推出的c++2a对std::shared_ptr做了完善。

先说c++17的改进,shared_ptr增加了opreator[],并可以使用int[]类的数组类型做模板参数,所以sp3的定义可以简化了:

std::shared_ptr<int[]> sp3(new int[10]());

对于访问分配的空间,可以将sp3.get()[index]替换为sp3[index]。看个具体的例子:

#include <iostream>
#include <memory>int main()
{std::shared_ptr<int[]> sp(new int[5]());for (int i = 0; i < 5; ++i) {sp[i] = (i+1) * (i+1);}for (int i = 0; i < 5; ++i) {std::cout << sp[i] << std::endl;}
}

我们分配一个有5个int元素的动态数组,然后分别赋值1-5的平方,然后输出:

g++ -Wall -std=c++17 test.cpp
./a.out1
4
9
16
25

使用被极大得简化了,然而还是有点问题,那就是无法使用std::make_shared,而我们除非指定自己的delete functor,否则我们应该尽量使用std::make_shared

所以c++20对此做了改进:

auto up2 = std::make_unique<int[]>(10); // 从c++14开始,分配一个管理有10个int元素的动态数组的unique_ptr// c++2a中你可以这样写,与上一句相似,只不过返回的是shared_ptr
auto sp3 = std::make_shared<int[]>(10);

在我的编译器上(GCC 8.2.1)还不能支持这一特性,所以很遗憾得不能提供演示了。

不过等c++2a(很可能就叫c++20)发布后std::shared_ptr就能安全而便捷地管理动态数组了。

这篇关于shared_ptr和动态数组的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1052727

相关文章

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法

《JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法》:本文主要介绍JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法,每种方法结合实例代码给大家介绍的非常... 目录引言:为什么"相等"判断如此重要?方法1:使用some()+includes()(适合小数组)方法2

Java中数组与栈和堆之间的关系说明

《Java中数组与栈和堆之间的关系说明》文章讲解了Java数组的初始化方式、内存存储机制、引用传递特性及遍历、排序、拷贝技巧,强调引用数据类型方法调用时形参可能修改实参,但需注意引用指向单一对象的特性... 目录Java中数组与栈和堆的关系遍历数组接下来是一些编程小技巧总结Java中数组与栈和堆的关系关于

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到

Java中的数组与集合基本用法详解

《Java中的数组与集合基本用法详解》本文介绍了Java数组和集合框架的基础知识,数组部分涵盖了一维、二维及多维数组的声明、初始化、访问与遍历方法,以及Arrays类的常用操作,对Java数组与集合相... 目录一、Java数组基础1.1 数组结构概述1.2 一维数组1.2.1 声明与初始化1.2.2 访问

一文详解SpringBoot中控制器的动态注册与卸载

《一文详解SpringBoot中控制器的动态注册与卸载》在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性,下面我们就来看看Sp... 目录项目结构1. 创建 Spring Boot 启动类2. 创建一个测试控制器3. 创建动态控制器注

MySQL查询JSON数组字段包含特定字符串的方法

《MySQL查询JSON数组字段包含特定字符串的方法》在MySQL数据库中,当某个字段存储的是JSON数组,需要查询数组中包含特定字符串的记录时传统的LIKE语句无法直接使用,下面小编就为大家介绍两种... 目录问题背景解决方案对比1. 精确匹配方案(推荐)2. 模糊匹配方案参数化查询示例使用场景建议性能优

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

springboot如何通过http动态操作xxl-job任务

《springboot如何通过http动态操作xxl-job任务》:本文主要介绍springboot如何通过http动态操作xxl-job任务的问题,具有很好的参考价值,希望对大家有所帮助,如有错... 目录springboot通过http动态操作xxl-job任务一、maven依赖二、配置文件三、xxl-

MySQL JSON 查询中的对象与数组技巧及查询示例

《MySQLJSON查询中的对象与数组技巧及查询示例》MySQL中JSON对象和JSON数组查询的详细介绍及带有WHERE条件的查询示例,本文给大家介绍的非常详细,mysqljson查询示例相关知... 目录jsON 对象查询1. JSON_CONTAINS2. JSON_EXTRACT3. JSON_TA