std::list环形实现中rebind分配器构造初始化问题
问题背景
尝试使用环形节点技巧实现支持自定义分配器的std::list,编写构造函数时遇到问题,当前实现代码如下:
#include <iostream> template <typename T, typename Alloc = std::allocator<T> > class List { private: struct BaseNode { BaseNode* prev = this; BaseNode* next = this; }; struct Node : BaseNode { T value; }; using AllocNode = typename std::allocator_traits<Alloc>::template rebind_alloc<Node>; using AllocTraits = std::allocator_traits<AllocNode>; BaseNode fake_base; size_t sz = 0; AllocNode alloc_node; public: explicit List(const Alloc& alloc = Alloc()) : alloc_node(AllocNode()) { } ~List() { BaseNode *cur_node = fake_base.next, *next_node; while (cur_node != &fake_base) { next_node = cur_node->next; AllocTraits::deallocate(alloc_node, (Node*)cur_node, 1); cur_node = next_node; } } };
实现中对Allocator执行rebind操作,存储适配Node类型的分配器实例,但不清楚如何在构造函数中使用类型为Allocator的入参alloc完成alloc_node的初始化,当前构造函数实现为:
explicit List (const Alloc& alloc = Alloc()) : alloc_node(AllocNode()) {}
核心疑问:
- 是否存在方法可以通过传入的
alloc参数构造alloc_node? - 如果无法实现,传入
alloc参数的意义是什么?
解答
完全可以通过传入的原始分配器参数构造rebind后的AllocNode实例,这也是标准容器的通用实现方式。
- 符合C++标准要求的分配器,都支持同族分配器的跨类型构造:同一分配器族下,针对不同类型rebind得到的分配器实例,可以直接互相构造,且共享底层内存资源。你通过
allocator_traits得到的AllocNode和入参Alloc属于同一分配器族,直接用传入的alloc作为构造参数初始化alloc_node即可,修正后的构造函数写法如下:
explicit List(const Alloc& alloc = Alloc()) : alloc_node(alloc) { }
- 你当前的写法是错误的:直接默认构造
AllocNode()会完全丢弃用户传入的自定义分配器状态,如果用户传入的是有状态分配器(比如绑定了专属内存池、配置了特定内存分配规则的分配器),这种写法会导致用户的自定义配置完全失效,甚至可能出现内存分配、释放使用不同分配器实例的未定义行为。 - 额外注意:当前析构函数存在逻辑漏洞,仅释放了Node的内存,没有调用Node内存储的T类型对象的析构函数。正确的销毁流程应该先通过
AllocTraits::destroy(alloc_node, std::addressof(static_cast<Node*>(cur_node)->value))销毁值对象,再执行内存释放操作。
内容的提问来源于stack exchange,提问作者Amir Mokhammed-Ali
相关产品推荐
相关产品推荐

