我实现了自定义分配器和自定义列表容器,它支持此分配器。它们的定义如下:
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 *'转换为'Node *'
我不确定我做错了什么,我错过了什么。那么,我该如何解决呢?在自定义容器中使用重新绑定的正确方法是什么?
修改
这就是我的自定义容器现在的样子:
//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;
}
答案 0 :(得分:2)
这些是分配器的要求: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;
}