vector类[]运算符重载需求:跨元素全局索引字符串字符
实现全局字符索引的vector重载方案
嗨,这个需求很实用——相当于给vector<string>构建一个扁平化的字符访问层,让你不用手动计算每个字符串的长度偏移,直接用全局索引就能读写所有串联起来的字符。不过要注意:我们不能直接重载std::vector的operator[](标准库类不允许用户随意修改),所以最佳方案是封装一个自定义类,内部持有vector<string>,然后实现我们想要的索引逻辑。
完整实现代码
#include <vector> #include <string> #include <stdexcept> // 用于抛出越界异常 class FlatStringVector { private: std::vector<std::string> vec; // 辅助函数:找到全局索引对应的字符串和内部偏移 std::pair<std::string*, size_t> find_string(size_t global_idx) { size_t current_offset = 0; for (auto& str : vec) { if (global_idx < current_offset + str.size()) { return {&str, global_idx - current_offset}; } current_offset += str.size(); } // 索引越界,抛出标准异常 throw std::out_of_range("FlatStringVector: global index out of bounds"); } // const版本的辅助函数 std::pair<const std::string*, size_t> find_string(size_t global_idx) const { size_t current_offset = 0; for (const auto& str : vec) { if (global_idx < current_offset + str.size()) { return {&str, global_idx - current_offset}; } current_offset += str.size(); } throw std::out_of_range("FlatStringVector: global index out of bounds"); } public: // 构造函数:直接接受vector<string> explicit FlatStringVector(std::vector<std::string> v) : vec(std::move(v)) {} // 非const版本:支持修改字符 char& operator[](size_t global_idx) { auto [str_ptr, local_idx] = find_string(global_idx); return (*str_ptr)[local_idx]; } // const版本:支持只读访问 const char& operator[](size_t global_idx) const { auto [str_ptr, local_idx] = find_string(global_idx); return (*str_ptr)[local_idx]; } // 可选:获取全局总字符数 size_t total_chars() const { size_t count = 0; for (const auto& str : vec) { count += str.size(); } return count; } // 可选:暴露内部vector的其他接口,比如添加元素 void push_back(std::string str) { vec.push_back(std::move(str)); } };
测试示例
#include <iostream> int main() { FlatStringVector fsv({"dog", "cat", "parrot"}); // 读取全局索引的字符 std::cout << fsv[0] << std::endl; // 输出 'd' std::cout << fsv[3] << std::endl; // 输出 'c'(dog有3个字符,索引3是cat的第一个字符) std::cout << fsv[6] << std::endl; // 输出 'p'(dog+cat共6个字符,索引6是parrot的第一个字符) // 修改全局索引的字符 fsv[2] = 'x'; // dog变成 dox fsv[4] = 'z'; // cat变成 caz std::cout << fsv[2] << std::endl; // 输出 'x' std::cout << fsv[4] << std::endl; // 输出 'z' // 验证总字符数 std::cout << fsv.total_chars() << std::endl; // 输出 3+3+6=12 return 0; }
关键细节说明
- 为什么封装自定义类?:
std::vector是标准库类型,我们不能直接给它添加成员或重载运算符(这会导致未定义行为),所以封装是最安全的做法。 - 双版本operator[]:必须同时提供const和非const版本,这样无论是const的
FlatStringVector对象还是普通对象,都能正确调用对应的索引方法。 - 越界处理:和标准库容器保持一致,索引越界时抛出
std::out_of_range异常,避免出现未定义行为。 - 辅助函数复用:把查找字符串和偏移的逻辑抽成辅助函数,避免重复代码,同时让
operator[]的实现更简洁。
如果你需要更多扩展(比如插入/删除字符时自动调整全局索引),可以基于这个类继续添加对应的成员函数~
内容的提问来源于stack exchange,提问作者Caleb W.
相关产品推荐
相关产品推荐

