为STL容器实现不可拷贝不可移动包装器的优化方案问询
为STL容器实现禁用拷贝/移动构造的包装器的方案探讨
我想要为map、vector、unordered_map等STL容器编写一个禁用拷贝和移动构造函数的包装器,目前想到几种实现方案,但都存在不足:
方案1:通用模板包装
// 定义可实例化任意STL容器的NoCopyMove模板 template <typename V> struct NoCopyMove { public: using value_type = V; value_type& get() { return val_; } template <typename... Args> NoCopyMove(Args&&... args): val_(std::forward<Args>(args)...) {} private: NoCopyMove(const NoCopyMove&) = delete; NoCopyMove(NoCopyMove&&) = delete; value_type val_; };
该模板可以实例化为任意STL容器类型,通过get()函数访问内部容器实例。
不足:每次操作容器都需要调用get(),使用不够直观。
方案2:特定容器的公有继承实现
template <typename Key, typename T, typename Hash = std::hash<Key>, typename KeyEqual = std::equal_to<Key>, class Allocator = std::allocator<std::pair<const Key, T>>> class unordered_map_ncm : public std::unordered_map<Key, T, Hash, KeyEqual, Allocator> { // 继承基类的所有构造函数 using std::unordered_map<Key, T, Hash, KeyEqual, Allocator>::unordered_map; private: unordered_map_ncm(const unordered_map_ncm&) = delete; unordered_map_ncm(unordered_map_ncm&&) = delete; };
优点:无需调用get(),可以直接使用STL容器的原生接口,用法和原容器一致。
不足:STL容器没有虚析构函数,存在指针切割风险;且需要为每种STL容器单独实现,复用性差。
方案2':泛化的公有继承模板
template <template <typename...> class T, typename... Us> class NoCopyMove : public T<Us...> { public: using T<Us...>::T; private: NoCopyMove(const NoCopyMove&) = delete; NoCopyMove(NoCopyMove&&) = delete; }; // 为unordered_map定义别名 template<typename Key, typename T, typename Hash = std::hash<Key>, typename KeyEqual = std::equal_to<Key>, class Allocator = std::allocator<std::pair<const Key, T>>> using unordered_map_ncm = NoCopyMove<std::unordered_map, Key, T, Hash, KeyEqual, Allocator>;
改进:通过模板模板参数实现了对任意STL容器的适配,无需逐个实现。
不足:仍然存在指针切割的问题,基类指针指向派生类实例时,析构会出现未定义行为。
目前还没有找到一种既具备原生STL容器的易用性(无需额外调用get()),又能避免指针切割问题的实现方式,希望能得到可行的建议。
内容的提问来源于stack exchange,提问作者Aman Deep Gautam
相关产品推荐
相关产品推荐

