實現一個安全向量模板類 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
支持任意數據類型(如int
、double
、std::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_datas
(std::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
通過以下設計實現了“安全”與“兼容”的平衡:
- 安全訪問:
operator[]
和at()
越界時返回默認值或自動擴容,避免崩潰; - 接口兼容:模仿
std::vector
的構造函數、迭代器、容量管理接口,降低使用成本; - 高效轉換:支持與
std::vector
雙向轉換,兼容標準庫生態; - 性能優化:通過
emplace_back
完美轉發和復用std::vector
內存管理,保證效率。
適用于需要頻繁訪問元素且對穩定性要求高的場景。