如何将重新绑定与自定义分配器和自定义列表一起使用
How to use rebind with custom allocator and custom list
我实现了我的自定义分配器和自定义列表容器,它支持这个分配器。它们的定义如下:
template <typename T, size_t num_of_blocks = 16>
class MyAllocator {
public:
template <typename U>
struct rebind {
using other = MyAllocator<U, num_of_blocks>;
}
...dozens of standard methods
}
template <typename T, typename MyAlloc = std::allocator<Node<T>>>
class MyList {
private:
MyAlloc allocator;
...different methods which use allocator member
}
一切都很好。因此,在我的客户端代码中,我可以这样做:
auto my_list = MyList<int, MyAllocator<Node<int>,10>>{};
它工作没有错误,我看到,我的自定义分配器被使用了。但我不喜欢使用自定义分配器的方式。事实上,我希望我的客户端代码看起来像这样:
auto my_list = MyList<int, MyAllocator<int,10>>{};
我的第一次尝试是这样的:
template <typename T, typename MyAlloc = std::allocator<T>>
class MyList {
private:
//MyAlloc allocator; // remove this member and rebind allocator to another one
typedef typename MyAlloc::template rebind<Node<T>>::other node_alloc_type;
node_alloc_type allocator; // I expect that my allocator now is of type MyAllocator<Node<T>, num_of_blocks>
... all the rest left unchanged
}
但是,当我运行新客户端代码时:
auto my_list = MyList<int, MyAllocator<int,10>>{};
我收到以下错误消息:
无法在赋值中将"int*"转换为"节点*">
我不确定我做错了什么,我错过了什么。那么,我该如何解决它呢?在自定义容器中使用重新绑定的正确方法是什么?
编辑
这就是我的自定义容器现在的样子:
//MyList.h
#include <memory>
template<typename T>
struct Node
{
Node(): m_next(nullptr){}
Node(T const &t):
m_value(t),
m_next(nullptr)
{}
T m_value;
Node* m_next;
};
template<typename T, typename MyAllocator = std::allocator<Node<T>>>
class MyList
{
private:
Node<T>* m_head = nullptr;
Node<T>* m_tail = nullptr;
MyAllocator my_allocator;
public:
class Iterator
{
private:
Node<T>* m_Node;
public:
Iterator(Node<T>* Node): m_Node(Node) {};
bool operator==(const Iterator& other)
{
return this == &other || m_Node == other.m_Node;
}
bool operator!=(const Iterator& other)
{
return !operator==(other);
}
T operator*()
{
if (m_Node)
{
return m_Node->m_value;
}
return T();
}
Iterator operator++()
{
Iterator i = *this;
if (m_Node)
{
m_Node = m_Node->m_next;
}
return i;
}
};
template<typename... Args>
void emplace(T v)
{
auto new_Node = my_allocator.allocate(1);
my_allocator.construct(new_Node, v);
if (m_head)
{
m_tail->m_next = new_Node;
} else {
m_head = new_Node;
new_Node->m_next = nullptr;
}
m_tail = new_Node;
}
Iterator begin() const
{
return Iterator(m_head);
}
Iterator end() const
{
return Iterator(nullptr);
}
};
此时没有重新绑定,我必须像这样定义它
template<typename T, typename MyAllocator = std::allocator<Node<T>>>
class MyList
我想要的是这样定义它:
template<typename T, typename MyAllocator = std::allocator<T>>
class MyList
编辑
下面是带有标准分配器的客户端代码:
//main.cpp
#include "MyList.h"
int main()
{
MyList<int, std::allocator<Node<int>>> my_list;
//auto my_list = MyList<int, std::allocator<int>>; // will not work
for (int i = 0; i < 10; ++i)
{
my_list.emplace(i);
}
return 0;
}
以下是分配器的要求: http://en.cppreference.com/w/cpp/concept/Allocator
请注意,模板重新绑定是可选的。
以下是容器必须具备的内容列表,以便符合该概念。 http://en.cppreference.com/w/cpp/concept/AllocatorAwareContainer
是的,喘气。我徒劳地寻找了一个简单或至少是极简主义的例子。如果您只需要一个链表,并且您可以使用 C++11 或更高版本,请使用 std::forward_list。
以下在给出的示例中有效。
template<typename T, typename MyAllocator = std::allocator<T>>
class MyList
{
private:
using node_alloc_t = typename std::allocator_traits<MyAllocator>::
template rebind_alloc<Node<T>>;
// create an object of type node allocator
node_alloc_t node_alloc;
// etc ....
public:
template<typename T>
void emplace(T v)
{
Node<T>* new_Node = node_alloc.allocate(1);
// Etc...
}
// etc...
};
现在都在一起...
#include <memory>
#include <iostream>
template<typename T>
struct Node
{
Node() : m_next(nullptr) {}
Node(T const &t) :
m_value(t),
m_next(nullptr)
{}
T m_value;
Node<T>* m_next;
};
template<typename T, typename MyAllocator = std::allocator<T>>
class MyList
{
private:
using node_alloc_t = typename std::allocator_traits<MyAllocator>::
template rebind_alloc<Node<T>>;
// create an object of type node allocator
node_alloc_t node_alloc;
public:
class Iterator
{
private:
Node<T>* m_Node;
public:
Iterator(Node<T>* Node) : m_Node(Node) {};
bool operator==(const Iterator& other)
{
return this == &other || m_Node == other.m_Node;
}
bool operator!=(const Iterator& other)
{
return !operator==(other);
}
T operator*()
{
if (m_Node)
{
return m_Node->m_value;
}
return T();
}
Iterator operator++()
{
Iterator i = *this;
if (m_Node)
{
m_Node = m_Node->m_next;
}
return i;
}
};
template<typename T>
void emplace(T v)
{
Node<T>* new_Node = node_alloc.allocate(1);
node_alloc.construct(new_Node, v);
if (m_head)
{
m_tail->m_next = new_Node;
}
else {
m_head = new_Node;
new_Node->m_next = nullptr;
}
m_tail = new_Node;
}
Iterator begin() const
{
return Iterator(m_head);
}
Iterator end() const
{
return Iterator(nullptr);
}
};
int main()
{
MyList<int> my_list;
for (int i = 0; i < 10; ++i)
{
my_list.emplace(i);
}
for (auto i : my_list) {
std::cout << i << std::endl;
}
return 0;
}
相关文章:
- C++17 - 使用自定义分配器的节点提取/重新插入 - 适用于 clang++/libc++,但不适用于 libstd
- C++自定义分配器大小参数作为模板参数会引发编译器错误
- c++ 中的自定义分配器,用于不调用secure_string实现
- 我可以对 std::array 使用自定义分配器来获取安全加密密钥吗?
- shared_ptr的删除程序是否存储在自定义分配器分配的内存中?
- 自定义分配器,包括放置新案例
- 对 std::regex_match 使用自定义分配器
- 为什么我的代码不适用于自定义分配器?
- 为什么这个自定义分配器的析构函数在 GCC/MSVS 的 stdlib 中被调用两次
- std::cout 如果从自定义分配器 (Visual Studio 2019) 调用,则不会输出
- 通过自定义分配器和删除器有效使用shared_ptr
- 如何将带有自定义分配器的 std::vector 传递给期望带有 std::分配器的函数?
- 自定义分配器兼容性
- 使用自定义分配器及其替代项重载基本类型
- C 中STL地图的自定义分配器
- 带有 clang++ v4 和 gcc 6.3 库的自定义分配器
- 不调用带有 std::vector 的自定义分配器
- 何时使用自定义分配器
- 为什么当我使用自定义分配器溢出向量时没有出现分段错误?
- 如何将自定义分配器的完全相同状态传递给多个容器?