我正在尝试构建一个自定义分配器来从我自己的数据池中分配。 我从Microsoft站点的一些示例代码开始,这些代码似乎是自定义分配器的最小实现。
来自https://msdn.microsoft.com/en-us/library/aa985953.aspx的原始代码:
template <class T>
struct Mallocator
{
typedef T value_type;
Mallocator() noexcept {} //default ctor not required by STL
// A converting copy constructor:
template<class U> Mallocator(const Mallocator<U>&) noexcept {}
template<class U> bool operator==(const Mallocator<U>&) const noexcept
{
return true;
}
template<class U> bool operator!=(const Mallocator<U>&) const noexcept
{
return false;
}
T* allocate(const size_t n) const;
void deallocate(T* const p, size_t) const noexcept;
};
template <class T>
T* Mallocator<T>::allocate(const size_t n) const
{
if (n == 0)
{
return nullptr;
}
if (n > static_cast<size_t>(-1) / sizeof(T))
{
throw std::bad_array_new_length();
}
void* const pv = malloc(n * sizeof(T));
if (!pv) { throw std::bad_alloc(); }
return static_cast<T*>(pv);
}
template<class T>
void Mallocator<T>::deallocate(T * const p, size_t) const noexcept
{
free(p);
}
我需要在分配器中添加状态,我正在构建它。
我从根本上已经完成了所有功能,但对我是否做过“适当的”事情有疑问。方式。
修改后的代码:
template <class T>
struct Mallocator
{
typedef T value_type;
Mallocator() noexcept {} //default ctor not required by STL
Mallocator(my_allocator* cust_alloc) noexcept : _cust_alloc(cust_alloc) {}
// A converting copy constructor:
//template<class U> Mallocator(const Mallocator<U>&) noexcept {}
template<class U> Mallocator(const Mallocator<U>&src) noexcept
{
// this does not work:
// _cust_alloc = src._cust_alloc;
// this seems ugly, but does work...
_cust_alloc = const_cast<Mallocator<U>&>(src).custom_allocator();
}
template<class U> bool operator==(const Mallocator<U>&) const noexcept
{
return true;
}
template<class U> bool operator!=(const Mallocator<U>&) const noexcept
{
return false;
}
T* allocate(const size_t n) const;
void deallocate(T* const p, size_t) const noexcept;
my_allocator* custom_allocator(){ return _cust_alloc; }
private:
my_allocator *_cust_alloc;
};
template <class T>
T* Mallocator<T>::allocate(const size_t n) const
{
if (n == 0)
{
return nullptr;
}
if (n > static_cast<size_t>(-1) / sizeof(T))
{
throw std::bad_array_new_length();
}
void* const pv = _cust_alloc->allocate(n * sizeof(T));
if (!pv) { throw std::bad_alloc(); }
return static_cast<T*>(pv);
}
template<class T>
void Mallocator<T>::deallocate(T * const p, size_t) const noexcept
{
_cust_alloc->deallocate(p);
// free(p);
}
虽然这一切都在这一点上起作用,但我对是否可以或应该采取不同的行动有疑问。
问题1 - 我发现我需要将我的成员变量添加到复制构造函数中。这导致在私有时访问我的成员变量的问题。我最初发现这个不寻常,但我错过了复制构造函数使用&#39; U&#39;而不是&#39; T&#39;。我假设(正如原始代码中的注释可能表明的那样)我在这里从一个不同类型的分配器复制,这意味着我正在复制一个不同的类,这解释了为什么我不能&#39;# 39,见&#39;私人会员直接。为了解决这个问题,我添加了一个访问器并对其进行了const_casted。这感觉很麻烦,我很想把成员变量公之于众。有没有更好的方法来形成这部分代码?解释&#39; T&#39;和&#39; U&#39;可能也会有所帮助。
问题2 - 在我写这篇文章时的研究中,我注意到了移动构造函数,完美转发等的参考资料。我不太熟悉,不知道创建和编写移动构造函数的细微差别。此外,我不知道是否需要一个,除非默认移动构造函数没有移动我的私有成员变量的问题。我不确定是否或何时在STL容器的上下文中调用移动构造函数。
在我正在做的事情的背景下,需要这样的东西,它是如何正确形成的?
template<class U> Mallocator(const Mallocator<U>&& src) noexcept
{
return std::forward<U>(src);
}
问题3 - 总的来说,是否有一些被接受的&#39;如何添加状态&#39;一个比我更好的自定义分配器? (我在这里完全错过了,还是我在正确的轨道上?)