指针重新绑定的目的是什么?
What is the purpose of pointer rebind?
我正在尝试实施 std::list
(MSVC)。还有一件事我无法理解:
template <class _Value_type, class _Voidptr> // voidptr? For what?
struct _List_node { // list node
using value_type = _Value_type;
using _Nodeptr = _Rebind_pointer_t<_Voidptr, _List_node>; // what is the purpose of such rebind?
...
}
我明白分配器重新绑定的原因,但是指针?我为什么要使用它以及在哪里使用它?
UPD:我明白了,什么是重新绑定。我的意思是,为什么不只是 _Nodeptr*
?为什么我需要重新绑定? (感谢 Evg)
用户使用 value_type.
实例化列表
例如,对于 list<int>
,value_type
将是 int
。
此外,列表分配器(也可以提供)为 value_type
的对象分配内存。
但是 value_type
不是 列表内部包含的内容。
该列表内部包含 **Nodes**
,value_type 是其成员。
因此,为了能够将分配和指针从 value_type
转换为 Node
(至少包含 value_type 和指向下一个节点的指针),使用了重新绑定。
相反,例如 vector<int>
则不需要。
这是因为 vector 的内部表示通常会在内部保存指向 value_type 对象数组的指针,在本例中是 int。所以这里不需要重新绑定。
这个问题的答案也来自分配器。我们来看看 _Rebind_pointer_t
是如何 defined:
template <class _Ptr, class _Ty>
using _Rebind_pointer_t = typename pointer_traits<_Ptr>::template rebind<_Ty>;
也就是说,我们有
template <class _Value_type, class _Voidptr>
struct _List_node {
using _Nodeptr = typename pointer_traits<_Voidptr>::template rebind<_List_node>;
// ...
}
现在让我们来看看_List_node
是如何used:
using _Node = _List_node<_Ty, typename _Alty_traits::void_pointer>;
实际上,我们将分配器的 void_pointer
重新绑定到 _List_node
指针。需要这个技巧来支持在内部使用奇特指针的分配器。
可以在 Boost.Interprocess 库中找到一个这样的例子。它有 boost::interprocess::allocator:
An STL compatible allocator that uses a segment manager as memory source. The internal pointer type will of the same type (raw, smart) as typename SegmentManager::void_pointer
type. This allows placing the allocator in shared memory, memory mapped-files, etc...
比如我们可以这样写
namespace bi = boost::interprocess;
using Allocator = bi::allocator<int, bi::managed_shared_memory::segment_manager>;
std::list<int, Allocator> list(/* allocator object */);
现在 std::allocator_traits<decltype(list)::allocator_type>::void_pointer
将不是默认分配器的 void*
,而是 boost::interprocess::offset_ptr<void, ...>
。结果,_Nodeptr
将不是 _Nodeptr*
,而是 boost::interprocess::offset_ptr<_Nodeptr, ...>
。
我正在尝试实施 std::list
(MSVC)。还有一件事我无法理解:
template <class _Value_type, class _Voidptr> // voidptr? For what?
struct _List_node { // list node
using value_type = _Value_type;
using _Nodeptr = _Rebind_pointer_t<_Voidptr, _List_node>; // what is the purpose of such rebind?
...
}
我明白分配器重新绑定的原因,但是指针?我为什么要使用它以及在哪里使用它?
UPD:我明白了,什么是重新绑定。我的意思是,为什么不只是 _Nodeptr*
?为什么我需要重新绑定? (感谢 Evg)
用户使用 value_type.
实例化列表
例如,对于 list<int>
,value_type
将是 int
。
此外,列表分配器(也可以提供)为 value_type
的对象分配内存。
但是 value_type
不是 列表内部包含的内容。
该列表内部包含 **Nodes**
,value_type 是其成员。
因此,为了能够将分配和指针从 value_type
转换为 Node
(至少包含 value_type 和指向下一个节点的指针),使用了重新绑定。
相反,例如 vector<int>
则不需要。
这是因为 vector 的内部表示通常会在内部保存指向 value_type 对象数组的指针,在本例中是 int。所以这里不需要重新绑定。
这个问题的答案也来自分配器。我们来看看 _Rebind_pointer_t
是如何 defined:
template <class _Ptr, class _Ty>
using _Rebind_pointer_t = typename pointer_traits<_Ptr>::template rebind<_Ty>;
也就是说,我们有
template <class _Value_type, class _Voidptr>
struct _List_node {
using _Nodeptr = typename pointer_traits<_Voidptr>::template rebind<_List_node>;
// ...
}
现在让我们来看看_List_node
是如何used:
using _Node = _List_node<_Ty, typename _Alty_traits::void_pointer>;
实际上,我们将分配器的 void_pointer
重新绑定到 _List_node
指针。需要这个技巧来支持在内部使用奇特指针的分配器。
可以在 Boost.Interprocess 库中找到一个这样的例子。它有 boost::interprocess::allocator:
An STL compatible allocator that uses a segment manager as memory source. The internal pointer type will of the same type (raw, smart) as
typename SegmentManager::void_pointer
type. This allows placing the allocator in shared memory, memory mapped-files, etc...
比如我们可以这样写
namespace bi = boost::interprocess;
using Allocator = bi::allocator<int, bi::managed_shared_memory::segment_manager>;
std::list<int, Allocator> list(/* allocator object */);
现在 std::allocator_traits<decltype(list)::allocator_type>::void_pointer
将不是默认分配器的 void*
,而是 boost::interprocess::offset_ptr<void, ...>
。结果,_Nodeptr
将不是 _Nodeptr*
,而是 boost::interprocess::offset_ptr<_Nodeptr, ...>
。