安全向量模板类SiVector

实现一个安全向量模板类 SiVector,其设计目标是:在保持 std::vector 易用性的基础上,增强越界访问的安全性(避免崩溃),同时兼容 std::vector 的核心接口和使用习惯。支持嵌套使用(如 SiVector<std::vector<double>>),提供越界访问时的默认值返回或自动扩容机制,并支持与 std::vector 的双向类型转换。

实现

代码示例

#include <string>
#include <iostream>
#include <vector>
#include <iterator>template <typename T>
class SiVector {
public:SiVector(T value) : m_defaultValue(value) {}SiVector(std::vector<T> data) : m_datas(data) {}SiVector(std::vector<T> data, T value) : m_datas(data), m_defaultValue(value) {}// ========== 构造函数:模仿std::vector ==========SiVector() : m_defaultValue(T()) {} // 构造指定大小的容器,元素初始化为value(默认用默认值)explicit SiVector(uint32_t size, const T& value = T()) : m_datas(size, value), m_defaultValue(T()) {}// 从迭代器范围构造template <typename InputIt>SiVector(InputIt first, InputIt last): m_datas(first, last), m_defaultValue(T()) {}// 从初始化列表构造(支持 SiVector<int> v = {1,2,3};)SiVector(std::initializer_list<T> init) : m_datas(init), m_defaultValue(T()) {}// 拷贝构造SiVector(const SiVector& other) = default;// 移动构造SiVector(SiVector&& other) noexcept = default;// 类型别名:模仿std::vector的迭代器类型// using value_type = T;using iterator = typename std::vector<T>::iterator;using const_iterator = typename std::vector<T>::const_iterator;// using reference = T&;// using const_reference = const T&;// using size_type = size_t;// ========== 赋值操作:模仿std::vector ==========SiVector& operator=(const SiVector& other) = default;SiVector& operator=(SiVector&& other) noexcept = default;SiVector& operator=(std::initializer_list<T> init) {m_datas = init;return *this;}// 重载[]:越界时返回默认值(const版)T& operator[](uint32_t index) {if (index >= m_datas.size()) {std::cout << "index out of range.   ";m_datas.resize(index + 1, m_defaultValue);}return m_datas[index];}const T& operator[](uint32_t index) const {if (index >= m_datas.size()) {std::cout << "index out of range.   ";return m_defaultValue;}return m_datas[index];}T& at(uint32_t index) {if (index >= m_datas.size()) {std::cout << "at index out of range.    ";return m_defaultValue;}return m_datas[index];}const T& at(uint32_t index) const {if (index >= m_datas.size()) {std::cout << "at index out of range.    ";return m_defaultValue;}return m_datas[index];}// 首尾元素访问T& front() { return m_datas.front(); }const T& front() const { return m_datas.front(); }T& back() { return m_datas.back(); }const T& back() const { return m_datas.back(); }// ========== 迭代器:支持范围for循环 ==========iterator begin() noexcept { return m_datas.begin(); }// const_iterator const begin() noexcept { return m_datas.begin(); }const_iterator const cbegin() noexcept { return m_datas.cbegin(); }iterator end() noexcept { return m_datas.end(); }// const_iterator const end() noexcept { return m_datas.end(); }const_iterator const cend() noexcept { return m_datas.cend(); }// ========== 容量操作:与std::vector一致 ==========bool empty() const noexcept { return m_datas.empty(); }uint32_t const size() noexcept { return m_datas.size(); }uint32_t capacity() const noexcept { return m_datas.capacity(); }// 调整大小(多余元素用默认值填充)void resize(uint32_t size) { m_datas.resize(size, m_defaultValue); } void resize(uint32_t size , const T& value) { m_datas.resize(size, value); }// 预留容量void reserve(uint32_t size) { m_datas.reserve(size); }void shrink_to_fit() { m_datas.shrink_to_fit(); }operator std::vector<T>() const {return m_datas;}// ========== 修改操作:与std::vector一致 ==========void push_back(const T& value) { m_datas.push_back(value); }void push_back(T&& value) { m_datas.push_back(std::move(value)); }template <typename... Args>T& emplace_back(Args&&... args) { return m_datas.emplace_back(std::forward<Args>(args)...); } // std::forward<Args>(args)... 中的 ... 是必须的,它的作用是:将参数包 args 中的所有参数逐个展开,传递给 m_datas.emplace_back. 保持每个参数的转发语义(完美转发)void pop_back() {if (!m_datas.empty()) {m_datas.pop_back();}}// 插入元素(在pos位置插入value)iterator insert(const iterator pos, const T& value) {return m_datas.insert(pos, value);}iterator insert(const iterator pos, uint32_t size, const T& value) {return m_datas.insert(pos, size, value);}// 清除元素void clear() noexcept {m_datas.clear();}// 交换两个容器void swap(SiVector& other) noexcept {m_datas.swap(other.m_datas);std::swap(m_defaultValue, other.m_defaultValue);}operator std::vector<std::vector<T>>() const {std::vector<std::vector<T>> result;for (uint32_t i = 0; i< m_datas.size(); i++) {result.push_back(m_datas[i]);  }return result;}void setDefault(const T& defaultValue) {m_defaultValue = defaultValue;}private:std::vector<T> m_datas;T              m_defaultValue{0};
};int main() {std::vector<std::vector<double>> data{{0.2, 0.5}, {0.4, 100.5, 100.6}};SiVector<std::vector<double>>  vec(data);uint32_t index = 0;for (auto it : vec) {std::cout << "index[" << index << "]" << std::endl;index++;for (const auto& in : it) {std::cout << "value : " << in << std::endl; }}std::vector<std::vector<double>> vec1 = vec;index = 0;for (auto it : vec1) {std::cout << "index[" << index << "]" << std::endl;index++;for (const auto& in : it) {std::cout << "value : " << in << std::endl; }} std::cout << vec[10000][5000] << std::endl;std::vector<double> vec2 = vec[3];// 访问vec2[5]有可能崩溃std::cout << vec2[5] << vec2.size() << std::endl;return 1;
}

重点解释

1. 类定义与模板基础
template <typename T>
class SiVector { ... };
  • template <typename T>:模板类定义,使 SiVector 支持任意数据类型(如 intdoublestd::vector<double> 等),具备通用性。
  • 核心成员:
    • m_datas:内部使用 std::vector<T> 存储数据,复用标准容器的内存管理逻辑;
    • m_defaultValue:越界访问时返回的默认值(通过 setDefault 可自定义)。
2. 构造函数:兼容 std::vector 的初始化方式

SiVector 提供了多种构造函数,覆盖 std::vector 的常见初始化场景:

// 无参构造
SiVector() : m_defaultValue(T()) {} // 指定大小和初始值构造(explicit避免隐式类型转换)
explicit SiVector(uint32_t size, const T& value = T()) : m_datas(size, value), m_defaultValue(T()) {}// 迭代器范围构造(支持从其他容器复制元素)
template <typename InputIt>
SiVector(InputIt first, InputIt last): m_datas(first, last), m_defaultValue(T()) {}// 初始化列表构造(支持 SiVector<int> v = {1,2,3}; 语法)
SiVector(std::initializer_list<T> init) : m_datas(init), m_defaultValue(T()) {}// 拷贝构造与移动构造(=default 复用编译器默认实现)
SiVector(const SiVector& other) = default;
SiVector(SiVector&& other) noexcept = default;
  • explicit:修饰单参数构造函数,避免意外的隐式类型转换(如 SiVector<int> v = 5; 会编译报错,需显式构造)。
  • = default:对拷贝/移动构造使用默认实现,编译器会自动生成“逐成员拷贝/移动”的逻辑,简洁高效。
3. 元素访问:安全的 operator[]at()

SiVector 的核心安全特性体现在元素访问接口,解决了 std::vector 越界访问崩溃的问题:

(1)operator[] 重载
// 非const版本:越界时自动扩容(保证修改操作安全)
T& operator[](uint32_t index) {if (index >= m_datas.size()) {std::cout << "index out of range.   ";m_datas.resize(index + 1, m_defaultValue);  // 扩容并填充默认值}return m_datas[index];
}
// const版本:越界时返回默认值(只读场景不修改容器)
const T& operator[](uint32_t index) const {if (index >= m_datas.size()) {std::cout << "index out of range.   ";return m_defaultValue;  // 不扩容,返回默认值}return m_datas[index];
}
  • 核心逻辑:通过 index >= m_datas.size() 检查越界,非const对象越界时自动扩容(确保后续访问有效),const对象越界时返回默认值(避免修改const对象)。
  • 优势:既避免了 std::vector::operator[] 越界导致的未定义行为(崩溃/数据错乱),又保持了类似数组的便捷访问语法。
(2)at() 方法
T& at(uint32_t index) {if (index >= m_datas.size()) {std::cout << "at index out of range.    ";return m_defaultValue;  // 越界返回默认值(与std::vector::at()抛异常不同)}return m_datas[index];
}
  • std::vector::at() 不同:std::vector::at() 越界会抛出 std::out_of_range 异常,而 SiVector::at() 越界返回默认值,进一步避免程序终止。
4. 迭代器:支持范围for循环
// 类型别名:复用std::vector的迭代器类型
using iterator = typename std::vector<T>::iterator;
using const_iterator = typename std::vector<T>::const_iterator;// 迭代器接口
iterator begin() noexcept { return m_datas.begin(); }
const_iterator cbegin() noexcept { return m_datas.cbegin(); }
iterator end() noexcept { return m_datas.end(); }
const_iterator cend() noexcept { return m_datas.cend(); }
  • 作用:通过提供 begin()/end() 等迭代器接口,SiVector 支持 C++ 范围for循环(for (auto x : vec) { ... }),语法与 std::vector 完全一致。
  • 实现逻辑:直接复用内部 m_datasstd::vector)的迭代器,无需手动实现迭代器逻辑,简化代码且保证兼容性。
5. 容量管理:与 std::vector 行为一致
// 容量操作
uint32_t const size() noexcept { return m_datas.size(); }  // 实际元素数量
uint32_t capacity() const noexcept { return m_datas.capacity(); }  // 已分配内存容量
void resize(uint32_t size) { m_datas.resize(size, m_defaultValue); }  // 调整大小(填充默认值)
void reserve(uint32_t size) { m_datas.reserve(size); }  // 预分配容量(不改变大小)
void shrink_to_fit() { m_datas.shrink_to_fit(); }  // 收缩容量至实际大小
  • 这些接口与 std::vector 功能完全一致,确保用户可以像管理 std::vector 一样管理 SiVector 的内存(如预分配容量提升性能、收缩容量节省内存)。
6. 类型转换:与 std::vector 双向兼容

SiVector 定义了类型转换运算符,支持与 std::vector 无缝转换:

// 转换为单层std::vector<T>
operator std::vector<T>() const {return m_datas;
}// 转换为嵌套std::vector<std::vector<T>>(针对嵌套SiVector)
operator std::vector<std::vector<T>>() const {std::vector<std::vector<T>> result;for (uint32_t i = 0; i < m_datas.size(); i++) {result.push_back(m_datas[i]);  }return result;
}
  • 使用场景:当需要调用接受 std::vector 参数的函数时,SiVector 对象可自动转换为 std::vector,无需手动拷贝(如 std::vector<std::vector<double>> vec1 = vec;)。
7. 修改操作:高效元素添加/删除
// 尾部添加元素(支持拷贝和移动语义)
void push_back(const T& value) { m_datas.push_back(value); }
void push_back(T&& value) { m_datas.push_back(std::move(value)); }// 原地构造元素(避免拷贝,高效)
template <typename... Args>
T& emplace_back(Args&&... args) { return m_datas.emplace_back(std::forward<Args>(args)...); 
}
  • emplace_back 与完美转发
    • Args&&... args 是可变参数模板(参数包),支持任意数量和类型的参数;
    • std::forward<Args>(args)... 中的 ... 用于展开参数包,将参数“完美转发”给 m_datas.emplace_back,实现元素在容器内部直接构造(无需临时对象拷贝),性能优于 push_back
8. main 函数示例解析
int main() {// 1. 初始化嵌套SiVector(从std::vector<std::vector<double>>构造)std::vector<std::vector<double>> data{{0.2, 0.5}, {0.4, 100.5, 100.6}};SiVector<std::vector<double>>  vec(data);// 2. 范围for循环遍历(依赖迭代器实现)for (auto it : vec) { ... }// 3. 转换为std::vector并遍历std::vector<std::vector<double>> vec1 = vec;// 4. 越界访问测试(非const版本自动扩容)std::cout << vec[10000][5000] << std::endl;  // 外层越界自动扩容,内层同理// 5. 验证转换后的std::vector越界行为(可能崩溃,体现SiVector的安全性)std::vector<double> vec2 = vec[3];std::cout << vec2[5] << vec2.size() << std::endl;  // std::vector越界是未定义行为
}
  • 示例展示了 SiVector 的核心特性:嵌套使用、范围遍历、类型转换、安全越界访问,同时对比了 std::vector 越界的风险,突出 SiVector 的安全性。

总结

SiVector 通过以下设计实现了“安全”与“兼容”的平衡:

  1. 安全访问operator[]at() 越界时返回默认值或自动扩容,避免崩溃;
  2. 接口兼容:模仿 std::vector 的构造函数、迭代器、容量管理接口,降低使用成本;
  3. 高效转换:支持与 std::vector 双向转换,兼容标准库生态;
  4. 性能优化:通过 emplace_back 完美转发和复用 std::vector 内存管理,保证效率。

适用于需要频繁访问元素且对稳定性要求高的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/920344.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/920344.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cloudflare 推出 GenAI 安全工具,守护企业数据

8 月 26 日,Cloudflare 为其企业平台 Cloudflare One 推出了新的安全功能,帮助企业安全地采用 ChatGPT、Claude 和 Gemini 等生成式 AI 工具。该工具构建为云访问安全代理 (CASB),通过 API 集成来监控和保护这些 AI 服务,无需安装设备。 随着企业对 GenAI 的使用激增——C…

Mac测试端口连接的几种方式

在 macOS 上测试端口是否开放&#xff0c;可通过以下三种常用方法实现&#xff08;推荐优先使用系统自带的 nc 命令&#xff0c;简单高效&#xff09;&#xff1a;方法 1&#xff1a;用系统自带 nc&#xff08;netcat&#xff09;测试&#xff08;最推荐&#xff09;nc 是 macO…

用PyTorch实现多类图像分类:从原理到实际操作

引言 图像分类作为计算机视觉的基石&#xff0c;已深度渗透到我们生活的方方面面——从医疗影像中早期肿瘤的识别、自动驾驶汽车对道路元素的实时检测&#xff0c;到卫星图像的地形分析与零售行业的商品识别&#xff0c;其核心都是让机器学会"看懂"世界并做出分类决…

window安装python环境

1、确认操作系统类型和位数&#xff0c;明确下载安装包的版本&#xff0c;示例为&#xff1a;windows&#xff0c;64位环境。 2、登录python官网下载exe安装包&#xff0c;下载网址&#xff1a;Download Python | Python.org 找到想要的对应python版本&#xff0c;本次示例下…

用 Streamlit 构建一个简易对话机器人 UI

在这篇文章中&#xff0c;我将演示如何用 Streamlit 快速构建一个轻量的对话机器人 UI&#xff0c;并通过 LangChain / LangGraph 调用 LLM&#xff0c;实现简单的对话功能。通过将前端和后端分离&#xff0c;你可以单独测试模型调用和 UI 显示。为什么选择 Streamlit&#xff…

【Redis 进阶】Redis 典型应用 —— 缓存(cache)

一、什么是缓存 缓存&#xff08;cache&#xff09;是计算机中的一个经典的概念&#xff0c;在很多场景中都会涉及到。核心思路就是把一些常用的数据放到触手可及&#xff08;访问速度更快&#xff09;的地方&#xff0c;方便随时读取。 举例&#xff1a;我需要去高铁站坐高铁…

RK3588 Ubuntu22.04 解决eth0未托管问题

在调试rk3588的Ubuntu的时候发现&#xff0c;网络那里一直显示eth0未托管&#xff0c;但是联网功能又是正常的&#xff0c;猜测是某一个配置文件的问题修改如下&#xff1a;打开/etc/NetworkManager/NetworkManager.conf&#xff0c;将managed&#xff0c;修改成true即可然后重…

雷卯针对香橙派Orange Pi 3G-IoT-B开发板防雷防静电方案

一、应用场景计算机、无线网络服务器、游戏机、音乐播放器、高清视频播放器、扬声器、Android 设备、Scratch 编程平台二、核心功能参数三、扩展接口详情雷卯专心为您解决防雷防静电的问题&#xff0c;有免费实验室供检测。开发板资料转自深圳迅龙软件。谢谢&#xff01;

Science Robotics 丰田研究院提出通过示例引导RL的全身丰富接触操作学习方法

人类表现出非凡的能力&#xff0c;可以利用末端执行器&#xff08;手&#xff09;的灵巧性、全身参与以及与环境的交互&#xff08;例如支撑&#xff09;来纵各种大小和形状的物体。 人类灵活性的分类法包括精细和粗略的作技能。尽管前者&#xff08;精细灵巧性&#xff09;已在…

趣丸游戏招高级业务运维工程师

高级业务运维工程师趣丸游戏 广州职位描述1、负责公司AI业务线运维工作&#xff0c;及时响应、分析、处理问题和故障&#xff0c;保证业务持续稳定&#xff1b; 2、负责基于分布式、微服务、容器云等复杂业务的全生命周期的稳定性保障&#xff1b; 3、参与设计运维平台、工具、…

2025通用证书研究:方法论、岗位映射与四证对比

本文基于公开材料与典型招聘描述&#xff0c;对常见通用型或准入型证书做方法论级别的比较&#xff0c;不构成培训或报考建议&#xff0c;也不涉及任何招生、返现、团购等信息。全文采用统一术语与可复用模板&#xff0c;以减少“经验之争”&#xff0c;便于不同背景的读者独立…

在WSL2-Ubuntu中安装Anaconda、CUDA13.0、cuDNN9.12及PyTorch(含完整环境验证)

WSL 搭建深度学习环境&#xff0c;流程基本上是一样的&#xff0c;完整细节可参考我之前的博客&#xff1a; 在WSL2-Ubuntu中安装CUDA12.8、cuDNN、Anaconda、Pytorch并验证安装_cuda 12.8 pytorch版本-CSDN博客 之所以记录下来&#xff0c;是因为CUDA和cuDNN版本升级后&#x…

OpenFOAM中梯度场的复用(caching)和生命期管理

文章目录OpenFOAM中梯度场的复用(caching)和生命期管理一、缓存机制的目标二、如何实现缓存&#xff08;以 fvc::grad 为例&#xff09;1. 使用 IOobject::AUTO_WRITE 和注册名2. 示例&#xff1a;fvc::grad 的缓存实现&#xff08;简化逻辑&#xff09;三、生命期管理是如何实…

【Hot100】贪心算法

系列文章目录 【Hot100】二分查找 文章目录系列文章目录方法论Hot100 之贪心算法121. 买卖股票的最佳时机55. 跳跃游戏45. 跳跃游戏 II763. 划分字母区间方法论 Hot100 之贪心算法 121. 买卖股票的最佳时机 121. 买卖股票的最佳时机&#xff1a;给定一个数组 prices &#…

电子电气架构 --- 软件项目复杂性的驾驭思路

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…

SSE实时通信与前端联调实战

1.SSE 原理机制 sse 类似websocket,但是sse是单向的&#xff0c;不可逆的&#xff0c;只能服务端向客户端发送数据流 2.解决跨域问题 Access to XMLHttpRequest at http://127.0.0.1:8090/sse/doChat from origin http://127.0.0.1:3000 has been blocked by CORS policy: Re…

从传统到创新:用报表插件重塑数据分析平台

一、传统 BI 平台面临的挑战 在当今数字化时代&#xff0c;数据已成为企业决策的重要依据。传统的商业智能&#xff08;BI&#xff09;平台在数据处理和分析方面发挥了重要作用&#xff0c;但随着数据量的爆炸式增长和用户需求的日益多样化&#xff0c;其局限性也逐渐显现。 …

MySQL--MySQL中的DECIMAL 与 Java中的BigDecimal

1. 为什么需要 DECIMAL在数据库中&#xff0c;常见的数值类型有&#xff1a;INT、BIGINT → 整数&#xff0c;存储容量有限。FLOAT、DOUBLE → 浮点数&#xff0c;存储效率高&#xff0c;但存在精度丢失问题。DECIMAL(M, D) → 定点数&#xff0c;存储精确值。例子&#xff1a;…

低空无人机系统关键技术与应用前景:SmartMediaKit视频链路的基石价值

引言&#xff1a;低空经济的新兴格局 低空经济作为“新质生产力”的代表&#xff0c;正在从政策驱动、技术突破和市场需求的共振中走向产业化。2023年&#xff0c;中国低空经济的市场规模已超过 5000 亿元人民币&#xff0c;同比增长超过 30%。无人机&#xff08;UAV&#xff…

在Windows系统上升级Node.js和npm

在Windows系统上升级Node.js和npm&#xff0c;我推荐以下几种方法&#xff1a; 方法1&#xff1a;使用官网安装包&#xff08;最简单&#xff09; 访问 nodejs.org 下载Windows安装包&#xff08;.msi文件&#xff09; 运行安装包&#xff0c;选择"修复"或直接安装新…