C++用于扩展任意标准符合分配器的设计模式
我目前正在寻找扩展任意标准符合分配器类型的最佳方法。需要明确的是:我不想编写自定义分配器。我只想向已有的扩展或行为“添加”特定的扩展或行为。我创建了一个示例,展示了它的样子。请注意,以下代码仅用于说明目的。
#ifndef HPP_SMART_ALLOCATOR_INCLUDED
#define HPP_SMART_ALLOCATOR_INCLUDED
#include <memory>
#include <map>
template<typename T>
struct allocator_traits;
template<typename T, class allocator_type = std::allocator<T>>
class smart_allocator;
template<>
struct allocator_traits<void>
{
typedef std::allocator<void>::const_pointer const_pointer;
typedef std::allocator<void>::pointer pointer;
typedef std::allocator<void>::value_type value_type;
};
template<typename T>
struct allocator_traits
{
typedef typename std::allocator<T>::const_pointer const_pointer;
typedef typename std::allocator<T>::const_reference const_reference;
typedef typename std::allocator<T>::difference_type difference_type;
typedef typename std::allocator<T>::pointer pointer;
typedef typename std::allocator<T>::reference reference;
typedef typename std::allocator<T>::size_type size_type;
typedef typename std::allocator<T>::value_type value_type;
};
template<class allocator_type>
class smart_allocator<void, allocator_type>
: public allocator_traits<void>
{
public:
template<typename U> struct rebind { typedef smart_allocator<U, typename allocator_type::rebind<U>::other> other; };
};
template<typename T, class allocator_type>
class smart_allocator
: public allocator_traits<T>,
private allocator_type
{
public:
using typename allocator_traits<T>::const_pointer;
using typename allocator_traits<T>::const_reference;
using typename allocator_traits<T>::difference_type;
using typename allocator_traits<T>::pointer;
using typename allocator_traits<T>::reference;
using typename allocator_traits<T>::size_type;
using typename allocator_traits<T>::value_type;
template<typename U> struct rebind { typedef smart_allocator<U, typename allocator_type::rebind<U>::other> other; };
smart_allocator() throw() /*noexcept*/;
smart_allocator(allocator_type const&) throw() /*noexcept*/;
virtual ~smart_allocator() throw();
virtual ~smart_allocator()
{
std::map<pointer, size_type>::iterator i = this->m_map.begin();
while (i != this->m_map.end())
{
this->allocator_type::deallocate(i->first, i->second);
++i;
}
}
pointer allocate(size_type n, allocator_traits<void>::const_pointer hint = 0)
{
pointer p = this->allocator_type::allocate(n, hint);
this->m_map.insert(std::pair<pointer, size_type>(p, n));
return p;
}
void deallocate(pointer p, size_type n) /*noexcept*/
{
std::map<pointer, size_type>::iterator iter = this->m_map.find(p);
if (iter != this->m_map.end())
this->allocator_type::deallocate(iter->first, iter->second);
}
using allocator_type::address;
using allocator_type::construct;
using allocator_type::destroy;
using allocator_type::max_size;
private:
smart_allocator(smart_allocator const&) throw();
smart_allocator& operator=(smart_allocator const&);
std::map<pointer, size_type> m_map;
};
#endif /* HPP_SMART_ALLOCATOR_INCLUDED */
请考虑以下注意事项:
- 模板参数 allocator_type 可以是任何标准符合类型。它不限于 std::allocator。所有 STL 实现都使用相同的技术。
- 从 allocator_type 派生时,我们需要使用私有继承,因为 std::allocator 成员函数都不是虚拟的。然而, std::allocator& alloc = smart_allocator() 不会执行您可能期望的操作。
您认为这适用吗?
I'm currently searching for the best way to extend an arbitrary standard conform allocator type. To be clear: I don't want to write a custom allocator. I just want to "add" a specific extension or behavior to an already existing one. I've created a sample how this could look like. Please note, that the following code is just for illustration purpose.
#ifndef HPP_SMART_ALLOCATOR_INCLUDED
#define HPP_SMART_ALLOCATOR_INCLUDED
#include <memory>
#include <map>
template<typename T>
struct allocator_traits;
template<typename T, class allocator_type = std::allocator<T>>
class smart_allocator;
template<>
struct allocator_traits<void>
{
typedef std::allocator<void>::const_pointer const_pointer;
typedef std::allocator<void>::pointer pointer;
typedef std::allocator<void>::value_type value_type;
};
template<typename T>
struct allocator_traits
{
typedef typename std::allocator<T>::const_pointer const_pointer;
typedef typename std::allocator<T>::const_reference const_reference;
typedef typename std::allocator<T>::difference_type difference_type;
typedef typename std::allocator<T>::pointer pointer;
typedef typename std::allocator<T>::reference reference;
typedef typename std::allocator<T>::size_type size_type;
typedef typename std::allocator<T>::value_type value_type;
};
template<class allocator_type>
class smart_allocator<void, allocator_type>
: public allocator_traits<void>
{
public:
template<typename U> struct rebind { typedef smart_allocator<U, typename allocator_type::rebind<U>::other> other; };
};
template<typename T, class allocator_type>
class smart_allocator
: public allocator_traits<T>,
private allocator_type
{
public:
using typename allocator_traits<T>::const_pointer;
using typename allocator_traits<T>::const_reference;
using typename allocator_traits<T>::difference_type;
using typename allocator_traits<T>::pointer;
using typename allocator_traits<T>::reference;
using typename allocator_traits<T>::size_type;
using typename allocator_traits<T>::value_type;
template<typename U> struct rebind { typedef smart_allocator<U, typename allocator_type::rebind<U>::other> other; };
smart_allocator() throw() /*noexcept*/;
smart_allocator(allocator_type const&) throw() /*noexcept*/;
virtual ~smart_allocator() throw();
virtual ~smart_allocator()
{
std::map<pointer, size_type>::iterator i = this->m_map.begin();
while (i != this->m_map.end())
{
this->allocator_type::deallocate(i->first, i->second);
++i;
}
}
pointer allocate(size_type n, allocator_traits<void>::const_pointer hint = 0)
{
pointer p = this->allocator_type::allocate(n, hint);
this->m_map.insert(std::pair<pointer, size_type>(p, n));
return p;
}
void deallocate(pointer p, size_type n) /*noexcept*/
{
std::map<pointer, size_type>::iterator iter = this->m_map.find(p);
if (iter != this->m_map.end())
this->allocator_type::deallocate(iter->first, iter->second);
}
using allocator_type::address;
using allocator_type::construct;
using allocator_type::destroy;
using allocator_type::max_size;
private:
smart_allocator(smart_allocator const&) throw();
smart_allocator& operator=(smart_allocator const&);
std::map<pointer, size_type> m_map;
};
#endif /* HPP_SMART_ALLOCATOR_INCLUDED */
Please consider the following notes:
- The template argument allocator_type could be any standard conform type. It is not restricted to std::allocator. This is the same technique all STL implementations are using.
- We need to use private inheritance when deriving from allocator_type, because non of the std::allocator member functions are virtual. However, std::allocator& alloc = smart_allocator() wouldn't do what you might expect.
Do you think this is applicable?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您当然需要实现复制构造函数和复制赋值运算符,否则当容器按值传递分配器时,您的映射可能会被破坏(特别是您可能会导致双重删除)。可能还有其他我没有注意到的考虑因素。
You'd certainly need to implement a copy constructor and copy assignment operator, or your map may get mangled when containers pass the allocator around by value (specifically you could wind up double-deleting). There may be other considerations I didn't notice.
我立刻想到的是装饰器;正如参考文献所述,“装饰器对于使对象适应新情况很有用,而无需重写原始对象的代码。”如果我理解你的问题,这听起来就像你所追求的。
What came to mind immediately was the Decorator; as the reference notes, "Decorators are useful for adapting objects to new situations without re-writing the original object's code." Which, if I understand your question, sounds like what you are after.