[英]Writing a custom allocator
I'm trying to write a custom allocator, which preallocates space for a fixed number of elements. 我正在尝试编写一个自定义分配器,该分配器为固定数量的元素预分配了空间。 However, I have some problems with understanding the requirements. 但是,我在理解需求方面存在一些问题。
#pragma once
#ifndef _ALLOCATOR_H
#define _ALLOCATOR_H
template<typename T>
class Allocator
{
public:
// typedefs
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
public:
// convert an allocator<T> to allocator<U>
template<typename U>
struct rebind
{
typedef Allocator<U> other;
};
public:
explicit Allocator(void)
{
mCurElement = 0;
mMaxElements = 650000000;
mBase = reinterpret_cast<pointer>(::operator new(mMaxElements * sizeof(T)));
}
virtual ~Allocator(void)
{
::operator delete(mBase);
}
explicit Allocator(Allocator const &oOther)
{
mCurElement = oOther.mCurElement;
mMaxElements = oOther.mMaxElements;
mBase = oOther.mBase;
}
template<typename U>
explicit Allocator(Allocator<U> const &oOther)
{
mCurElement = 0;
mMaxElements = 650000000;
mBase = oOther.mBase;
}
// address
pointer address(reference r) { return &r; }
const_pointer address(const_reference r) { return &r; }
// memory allocation
pointer allocate(size_type nElements, typename std::allocator<void>::const_pointer = 0)
{
if (mCurElement > mMaxElements)
return NULL;
//pointer p = reinterpret_cast<pointer>(::operator new(cnt * sizeof(T)));
pointer p = &mBase[mCurElement];
mCurElement += nElements;
return p;
}
void deallocate(pointer pAddress, size_type)
{
//::operator delete(pAddress);
mCurElement--;
}
// size
size_type max_size() const
{
return std::numeric_limits<size_type>::max() / sizeof(T);
}
// construction/destruction
void construct(pointer pAddress, const T& oObject)
{
new(pAddress) T(oObject);
}
void destroy(pointer pAddress)
{
pAddress->~T();
}
bool operator==(Allocator const&) { return true; }
bool operator!=(Allocator const& oAllocator) { return !operator==(oAllocator); }
public:
T *getBase(void) const { return mBase; }
private:
static usize_t mId;
T *mBase;
usize_t mMaxElements;
usize_t mCurElement;
};
#endif // _ALLOCATOR_H
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <sstream>
#include <set>
#include <ctime>
#include "allocator.h"
typedef unsigned int uint_t;
typedef unsigned long long usize_t;
usize_t Allocator<usize_t>::mId;
void testStdAllocator(usize_t nIterations, usize_t nMaxValue)
{
std::set<usize_t, std::less<usize_t>, Allocator<usize_t>> st;
std::string id = "Standard Set";
clock_t start = clock();
for (usize_t i = 0; i < nIterations; i++)
{
usize_t val = (usize_t)(rand() % nMaxValue) + 1;
if (i % 1000000 == 0)
std::cout << id << " testing ... " << i << "/" << nIterations << "\r";
st.insert(val);
}
std::cout << id << " Elapsed: " << clock() - start << std::endl;
}
int main(int argc, char *argv[])
{
usize_t iterations = 650000000;
usize_t val = 6500000;
std::cout << "Allocator" << std::endl;
testStdAllocator(iterations, val);
return 0;
}
The problem I have is: 我有的问题是:
Why do I need the template <typename U> ...
? 为什么需要template <typename U> ...
? (I found an example and adpated it) (我找到了一个例子并采用了它)
When I made it compilable and tested it the std::set
apparently creates copies of the allocator, so I would have to pass around the pointer. 当我使其可编译并对其进行测试时, std::set
显然会创建分配器的副本,因此我将不得不传递指针。 I can use an std::shared_ptr
for that, but I don't really see why this should be needed in the first place. 我可以为此使用std::shared_ptr
,但是我真的不明白为什么首先需要这样做。
Apparently there is something about proxied containers where the template <typename U>
is needed for, but this again creates the additional problem of passing the pointer around for an (apparently) different allocator type. 显然,代理容器存在一些需要template <typename U>
的地方,但这又带来了另一个问题,即(显然)不同的分配器类型传递了指针。
So I would appreciate some pointers where I'm going wrong. 因此,我将感谢一些我犯错的地方。
When you pass an allocator to std::set<T, C A>
it is meant to have an allocate()
function allcoating space for T
objects. 当您将分配器传递给std::set<T, C A>
它意味着要为T
对象提供一个allocate()
函数allcoating空间。 However, the std::set<T, C, A>
will not allocate any T
object. 但是, std::set<T, C, A>
将不会分配任何T
对象。 It will, instead, allocate _Node<T>
objects where _Node
is some tree node representation capable of holding T
objects but also containing suitable pointers to other nodes. 相反,它将分配_Node<T>
对象,其中_Node
是一些树节点表示形式, _Node
可以保存T
对象,又可以包含指向其他节点的合适指针。
To allocate an object of _Node<T>
an allocator based on A
is needed. 要分配_Node<T>
的对象,需要基于A
的分配器。 This allocator's type is obtained from A::rebind<_Node<T>>::other
and initialized appropriately by passing the original allocator object (or an object created from that) as constructor argument. 此分配器的类型是从A::rebind<_Node<T>>::other
并通过将原始分配器对象(或从其创建的对象)作为构造函数参数进行了适当的初始化。
Of course, using stateful allocators does assume that you use the C++11 allocator model. 当然,使用有状态分配器确实假定您使用的是C ++ 11分配器模型。 Prior to C++11 allocators did not appropriately construct other allocators and they were essentially stateless. 在C ++ 11之前,分配器没有适当地构造其他分配器,并且它们基本上是无状态的。 In case you need to use code prior to C++11 but want to deal with allocators, you might want to use the containers from BSL : these are allocator aware and do compile with C++03 compilers. 如果您需要使用C ++ 11之前的代码但要处理分配器,则可能要使用BSL中的容器:这些容器可以识别分配器,并且可以使用C ++ 03编译器进行编译。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.