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

相关文章

Spring Gateway动态路由实现方案

《SpringGateway动态路由实现方案》本文主要介绍了SpringGateway动态路由实现方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随... 目录前沿何为路由RouteDefinitionRouteLocator工作流程动态路由实现尾巴前沿S

JavaScript对象转数组的三种方法实现

《JavaScript对象转数组的三种方法实现》本文介绍了在JavaScript中将对象转换为数组的三种实用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友... 目录方法1:使用Object.keys()和Array.map()方法2:使用Object.entr

Python动态处理文件编码的完整指南

《Python动态处理文件编码的完整指南》在Python文件处理的高级应用中,我们经常会遇到需要动态处理文件编码的场景,本文将深入探讨Python中动态处理文件编码的技术,有需要的小伙伴可以了解下... 目录引言一、理解python的文件编码体系1.1 Python的IO层次结构1.2 编码问题的常见场景二

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. 模糊匹配方案参数化查询示例使用场景建议性能优