安全向量模板类SiVector - 实践

news/2025/9/23 9:21:54/文章来源:https://www.cnblogs.com/lxjshuju/p/19106574

实现一个安全向量模板类 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.mzph.cn/news/912032.shtml

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

相关文章

ONCHAINID源码分析(二)

ONCHAINID源码分析(二)上一章节我们对ONCHAINID做了一个总览、对各个组成部分做了概要性质的讲解,然后着重对整套合约的部署框架和代理合约设计做了代码分析。这使得我们对整体有了一定的理解,本章我们继续学习ONCHA…

gl账号注册网站沧州网站优化价格

&#x1f31f; 前言 欢迎来到我的技术小宇宙&#xff01;&#x1f30c; 这里不仅是我记录技术点滴的后花园&#xff0c;也是我分享学习心得和项目经验的乐园。&#x1f4da; 无论你是技术小白还是资深大牛&#xff0c;这里总有一些内容能触动你的好奇心。&#x1f50d; &#x…

福田网站建设流程网站设计网页配色

std::future —C17 多线程 std::future C标准程序库使用future来模拟这类一次性事件&#xff1a;若线程需等待某个特定的一次性事件发生&#xff0c;则会以恰当的方式取得一个future&#xff0c;它代表目标事件&#xff1b;接着&#xff0c;该线程就能一边执行其他任务&#…

云服务器搭建网站教程苏州做外贸网站

【README】 本文转自bilibili《计算机组成原理&#xff08;哈工大刘宏伟&#xff09;》的视频讲解&#xff0c;非常棒&#xff0c;墙裂推荐&#xff1b; 【1】中断介绍 1&#xff09;作用&#xff1a;用中断系统实现了外设数据的输入输出&#xff1b; 还可以用于程序调试&…

东庄水利枢纽建设公司网站本地网站建设教程xampp

《精通Unix下C语言编程与项目实践》读书笔记(new)文章试读 不拘一个遍程序系列&#xff1a;编程序不能一个脑袋钻到底&#xff0c;有时要学会变通&#xff0c;即所谓的曲线救国。一、二、三、四职场规划&#xff1a;一些杂七杂八的职场感悟吧。不值钱的软件人才 精力充沛与事业…

展览馆网站建设西安做网站朋朋网络

工作中&#xff0c;经常遇到端口转发的情况。实现的方式很多种&#xff0c;个人感觉还是用nginx实现方便一些。我的环境是ubuntu 22.04, 路由器开通端口段全部映射到这台机器&#xff0c;然后再由它转发给各兄弟机。 /etc/nginx/nginx.conf, 文末位置加入&#xff1a; stream…

烟台招远网站建设牛杂网这类网站怎么做的

分类预测 | Matlab实现KOA-CNN-BiGRU-selfAttention多特征分类预测&#xff08;自注意力机制&#xff09; 目录 分类预测 | Matlab实现KOA-CNN-BiGRU-selfAttention多特征分类预测&#xff08;自注意力机制&#xff09;分类效果基本描述程序设计参考资料 分类效果 基本描述 1.M…

集客营销软件官方网站微营销

先上原链接&#xff0c;一个很不错的wpf图标库 : https://github.com/MahApps/MahApps.Metro.IconPacks提供了大量的图标可以用&#xff0c;如下图&#xff1a;&#xff08;部分截图&#xff09;简单分析了一下代码&#xff0c;并模仿它写一个图标类和简单的使用示例&#xff1…

织梦导航网站模板武安信息港

高盛&#xff0c;作为全球领先的金融机构之一&#xff0c;近日发布了一份报告&#xff0c;预测在科技巨头的涨势推动下&#xff0c;标普500指数年底前有望升至6000点。这一预测引起了市场的广泛关注&#xff0c;投资者们纷纷开始重新评估自己的投资策略。 David Kostin等策略师…

做淘宝店铺有哪些好的网站建设公众号官方网站

PyCryptodome是python一个强大的加密算法库&#xff0c;可以实现常见的单向加密、对称加密、非对称加密、非对称加密算法签名和流加密算法。 直接pip安装即可&#xff1a;pip install pycryptodome 官网地址&#xff1a;https://pypi.org/project/pycryptodome/ 一、base64编码…

最佳三维文件格式,以及怎么在线浏览编辑FBX/OBJ/GLB/GLTF

什么是专有 3D 文件格式专有 3D 文件类型是特定于特定软件或公司的格式。专有文件格式的示例包括.max (3ds Max)、.blend (Blender)、.c4d (Cinema 4D)。 这些 3D 文件格式通常因其专有软件的功能丰富的选项而受…

秸秆可以发酵吗网站建设吗莱芜杂谈话题

个人主页 水月梦镜花 个人专栏 C语言 &#xff0c;数据结构 文章目录 一、顺序表二、实现思路1.存储结构2.初始化顺序表(SeqListInit)3.销毁顺序表(SeqListDestroty)4.打印顺序表(SeqListPrint)5.顺序表尾插(SeqListPushBack)and检查容量(SeqListCheckCapacity)6.顺序表头插(Se…

欧美平面设计网站网站后台账户如何做会计分录

前言 由于需要使用不同的qt环境&#xff08;PySide&#xff0c;PyQt&#xff09;所以写了这个脚本&#xff0c;使用找到的随便一个rcc命令去转换qrc文件&#xff0c;然后将导入模块换成qtpy这个通用库(支持pyside2-6&#xff0c;pyqt5-6)&#xff0c;老版本的是Qt.py(支持pysi…

网站建设属开票核定税种网络设计实践课程报告

在游戏开发领域&#xff0c;虚拟世界游戏定制开发是一项引人注目的任务&#xff0c;旨在满足客户独特的需求和愿景&#xff0c;创造一个完全个性化的虚拟世界游戏。这种类型的游戏开发需要专业的技能、深刻的游戏开发知识和密切的与客户合作&#xff0c;以确保游戏满足客户的期…

站长之家音效南京较好的网站制作公司

下面的讨论是我对《对编程实现拟人智能可行性的论证》这篇文章的“赋值与对象的标志”这一节的展开讨论。 标志能够使我们更好的思维&#xff08;比如用轮廓标记物体对象&#xff0c;用兴奋强度标记回忆情况等等&#xff09;。有思维标志、信息标志&#xff0c;单纯标志、组合…

温泉酒店网站建设方案英文网站优化

今天发现一个很有意思的问题&#xff0c;正常解决项目中产生的循环依赖&#xff0c;是找出今天添加的注入代码&#xff0c;然后一个个加lazy试过去&#xff0c;会涉及到类中新增的注入 但是今天修改了某个serviceimpl的方法&#xff0c;加入了Async方法后 就发生循环依赖了 ai…

河北网站建设推广自己做的网站怎么发布视频教程

一、说明 本系列是关于学习如何使用 ROS2、Docker 和 Github 设计、设置和维护机器人项目。 先决条件 — ROS2 软件包的基本知识、实现发布者、订阅者、操作并连接它们。 我们之前在 ROS2 中了解了不同的部分。但是&#xff0c;在我们转向实际的基于硬件的项目之前&#xff0c;…

ChatGPT 在招聘诈骗领域的应用

ChatGPT 在招聘诈骗领域的应用作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!cnblogs博客 zhihu Github 公众号:一本正经的瞎扯事件经过 整个八月我都没有上班,在等待新的工作签证审批通过。 工作签证有…

FR报表下拉框高度(JS添加css样式方式)调整

FR报表下拉框高度调整解决方案 问题描述 在FR报表开发中,点击下拉框按钮后,下拉选项列表的高度太小,用户体验不佳。直接使用 $(.fr-combo-list).css("height","400px") 设置高度往往不生效,因…

基于Python+Vue开发的新闻管理系统源码+运行步骤

项目简介该项目是基于Python+Vue开发的新闻管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Python编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Pyt…