如何实现功能与std::vector一致且带有最大长度限制的C++容器?
可选实现方案
下面给出三种实现思路,按推荐优先级排序:
方案1:自定义分配器(最符合STL设计规范)
STL容器的内存分配行为完全由分配器控制,你只需要实现一个限制总分配大小的自定义分配器,就可以直接复用std::vector的全部功能,不需要修改容器本身的逻辑,是成本最低、兼容性最好的方案。
示例代码:
#include <vector> #include <stdexcept> template <typename T, size_t MaxSize> struct LimitedAllocator { using value_type = T; LimitedAllocator() = default; template <typename U> constexpr LimitedAllocator(const LimitedAllocator<U, MaxSize>&) noexcept {} T* allocate(size_t n) { if (n > MaxSize) { throw std::bad_alloc(); } return static_cast<T*>(std::allocator<T>{}.allocate(n)); } void deallocate(T* p, size_t n) noexcept { std::allocator<T>{}.deallocate(p, n); } template <typename U> struct rebind { using other = LimitedAllocator<U, MaxSize>; }; }; template <typename T, size_t MaxSize> bool operator==(const LimitedAllocator<T, MaxSize>&, const LimitedAllocator<T, MaxSize>&) { return true; } template <typename T, size_t MaxSize> bool operator!=(const LimitedAllocator<T, MaxSize>&, const LimitedAllocator<T, MaxSize>&) { return false; } // 别名定义,用起来和普通vector几乎一致 template <typename T, size_t MaxSize> using LimitedVector = std::vector<T, LimitedAllocator<T, MaxSize>>;
使用的时候直接声明LimitedVector<int, 10> vec;即可,所有std::vector的原生接口都可以正常使用,当元素数量超过10时会自动拒绝分配内存,符合你的需求。
方案2:私有继承+using导入成员
如果你不想自定义分配器,也可以用私有继承std::vector的方式减少封装工作量,这种方式完全规避了公有继承STL容器的多态析构风险,同时不需要手动实现全部接口:
#include <vector> #include <utility> template <typename T, size_t MaxSize> class LimitedVector : private std::vector<T> { public: // 导入所有不需要修改的原生接口 using std::vector<T>::begin; using std::vector<T>::end; using std::vector<T>::cbegin; using std::vector<T>::cend; using std::vector<T>::size; using std::vector<T>::empty; using std::vector<T>::operator[]; using std::vector<T>::at; using std::vector<T>::front; using std::vector<T>::back; using std::vector<T>::clear; using std::vector<T>::erase; // 其他不需要修改的接口都可以按这个方式一行导入 // 只需要重写会改变容器大小的接口 void push_back(const T& val) { if (size() < MaxSize) { std::vector<T>::push_back(val); } } void push_back(T&& val) { if (size() < MaxSize) { std::vector<T>::push_back(std::move(val)); } } template <typename... Args> decltype(auto) emplace_back(Args&&... args) { if (size() < MaxSize) { return std::vector<T>::emplace_back(std::forward<Args>(args)...); } } // 同理重写insert、resize、reserve等接口即可 };
这种方式只需要重写少数几个修改容器大小的接口,其余接口都可以通过using声明直接导入,维护成本远低于全手动封装。
方案3:公有继承(仅适合内部受限场景使用)
STL容器不推荐公有继承的核心原因是没有虚析构函数,如果出现用基类指针指向派生类对象再删除的情况会触发未定义行为。如果你能100%保证不会有这种多态使用的场景,公有继承也是可用的,代码量最小,但不推荐对外暴露的接口使用这种实现。
注意你之前的代码有两个错误:std::vector的push_back不是虚函数,override关键字没有作用;同时你调用了不存在的成员vec,应该直接调用基类的方法。
修正后的示例:
#include <vector> template <typename T, size_t MaxSize> class LimitedVector : public std::vector<T> { public: void push_back(const T& val) { if (this->size() < MaxSize) { std::vector<T>::push_back(val); } } // 其他需要修改的接口同理重写即可 };
内容的提问来源于stack exchange,提问作者TenderShortGoldenRetriever
相关产品推荐
相关产品推荐

