我的lallocator< T> [英] My lallocator<T>

查看:69
本文介绍了我的lallocator< T>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我经常对std :: basic-string的性能感到恼火,因为

的复杂内存分配器在后台工作以找到工作
std :: allocator< T>。基本上,在大多数情况下,性能并没有超过基于堆栈的C字符串的每个b $ b的形成。但是,

的舒适性以及对缓冲区溢出的隐式保护使得std ::

basic_string值得使用。所以我搜索了一种方法来拥有自己的基于堆栈的内存分配

。我提出了以下想法:

导致了一个叫做lallocator的课程(来自本地分配器)这听起来很有趣,因为lall唠叨的意思是

德语* g *)。

首先,我们有lallocator-class,它是当地的接口

为stl-object分配存储空间(我的lallocator不能用于

字符串)。对于所有大小的基于本地堆栈的

池,此类是相同的,以防止我们编译任何大小的派生stl-classes

我们使用。其次,有一个名为lallocator_buffer_if的类,它是我们为lallocator分配的本地存储的

接口。我为所有大小的本地分配的池定义了这个接口,以防止我之前提到的任何

secial-buffer-size-compiling。第三个是lallocator_buffer_if< T>,它被称为lallocator_buffer< T,缓冲区,

size> ;; T是缓冲区中常用的数据类型,缓冲区是可以由lallocator分配的

缓冲区的数量,大小是每个缓冲区的大小为
。每当有人试图在lallocator上执行一个allocate()时,就会有一个空闲缓冲区并且缓冲区大到足以满足

分配请求,我们'将从池中分配缓冲区;否则

我们回到std :: allocator。


这里有一个如何使用它的例子:


typedef std :: basic_string< char,char_traits< char> ;, lallocator< char> >

lallostring;


lallocator_buffer< char,5,128> lbc;

lallocator< char> lallo(& lbc);

lallostring lsTest(lallo);


lsTest =" sdsdass" ;;


不幸的是我的编译器不能吃下面的代码

来防止lallocator的显式实例< T> -object:


lallocator_buffer< char,5,128> lbc;

lallostring lsTest(lallocator< char>(& lbc));


有谁知道这里是否存在一致性问题或是这个

只是我的编译器的一个错误?

所以这里是我的lalloator(它不是完全符合标准我用了一个

技巧,以防止在lallocator_buffer_if中有一个额外的指针

导致我的代码不能用于理论C ++ - 实现;对所有
宗教开发人员抱歉:


模板< typename T>

class lallocator_buffer_if

{

protected:

模板< typename T,std :: size_t buffers,std :: size_t buffer_size>

朋友类lallocator_buffer;


模板< typename T> < br $>
朋友类lallocator;


私人:

lallocator_buffer_if(){}

T * pop_buffer( );

void push_buffer(T * pt);

bool is_yours(T * pt);


受保护:

union buffer_header

{

buffer_header * pbhNextFree;

T at [1];

};


protected:

std: :size_t m_buffer_size;

buffer_header * m_pbhFirstFree;

buffer_header * m_pbhBufferEnd;

};


模板< typename T>

inline

T * lallocator_buffer_if< T> :: pop_buffer()

{

buffer_header * pbh;


if((pbh = m_pbhFirstFree)== NULL)

返回NULL;


返回m_pbhFirstFree = pbh-> pbhNextFree,

& pbh-> at [0];

}

template< typename T>

inline

void lallocator_buffer_if< T> :: push_buffer(T * pt)

{

buffer_header * pbh ;


pbh =(buffer_header *)pt;

pbh-> pbhNextFree = m_pbhFirstFree;

m_pbhFirstFree = pbh;

}


模板< typename T>

inline

bool lallocator_buffer_if< T> ; :: is_yours(T * pt)

{

return(void *)pt> =(void *)this&&

pt< & m_pbhBufferEnd-> at [0];

}


模板< typename T,std :: size_t buffers,std :: size_t buffer_size>

class lallocator_buffer:public lallocator_buffer_if< T>

{

public:

lallocator_buffer();


私人:

联盟缓冲区

{

buffer_header bh;

T atUnReferenced [buffer_size];

};


私人:

缓冲区aBuffers [buffers];

};


模板< typename T,std :: size_t buffers,std :: size_t buffer_size>

inline

lallocator_buffer< T,buffers,buffer_size> :: lallocator_buffer()

{

buffer * pbuf,

* pbufNext;

for((pbuf =& aBuffers [buffers - 1],

pbufNext = NULL);

pbuf> = aBuffers;

(pbufNext = pbuf,

pbuf - = 1))

pbuf-> bh.pbhNextFree =& pbufNext-> b h;


m_buffer_size = buffer_size;

m_pbhBufferEnd =& aBuffers [buffers] .bh;

m_pbhFirstFree =& aBuffers [0] .bh;

}


模板< typename T>

类lallocator:public std :: allocator< T> ;

{

public:

lallocator(lallocator_buffer_if< T> * plbi);

lallocator(lallocator const& lc);

~lallocator(){};

指针分配(size_type count, void * hint = NULL);

void deallocate(指针ptr,size_type计数);

lallocator& operator =(lallocator const& lc);


public:

template< class Other>

struct rebind

{

typedef lallocator< Other>其他;

};


私人:

lallocator_buffer_if< T> * m_plbi;

};


模板< typename T>

inline

lallocator< T> ; :: lallocator(lallocator_buffer_if< T> * plbi):

std :: allocator< T>()

{

m_plbi = plbi ;

}


模板< typename T>

inline

lallocator< T> :: lallocator(lallocator const& lc):

std :: allocator< T>(lc)

{

m_plbi = lc.m_plbi;

}


模板< typename T>

inline

typename lallocator< T> ::指针lallocator< T> :: allocate(size_type count,

void *提示)

{

T * pt;


if(count> m_plbi-> m_buffer_size ||

(pt = m_plbi-> pop_buffer())== NULL)

return std :: allocator< T> :: allocate(count);


return pt;

}


模板< typename T>

inline

v oid lallocator< T> :: deallocate(指针ptr,size_type计数)

{

if(!m_plbi-> is_yours(ptr))

return(void)std :: allocator< T> :: deallocate(ptr,count);


m_plbi-> push_buffer(ptr);

}


模板< typename T>

inline

typename lallocator< T> & lallocator< T> :: operator =(lallocator const& lc)

{

返回m_plbi = lc.m_plbi,

*这个;

}


[见 http://www.gotw.ca/resources/clcm.htm 有关的信息]

[comp.lang.c ++。moderated 。第一次海报:做到这一点! ]


[comp.std.c ++被审核。要提交文章,请尝试发布]

[您的新闻阅读器。如果失败,请使用mailto:st ***** @ ncar.ucar.edu]

[---请在发布前查看常见问题解答。 ---]

[常见问题: http://www.jamesd.demon.co.uk/csc/faq.html ]


I was often annoyed about the performance of std::basic-string because
of complex memory-allocators working in the background to found the work
of std::allocator<T>. Basically, the performance doesn''t reeach the per-
formance of a stack-based C-string in most cases. But nevertheless, the
comfort and the implicit protection against buffer-overflows makes std::
basic_string woth to be used. So I searched for a way to have my own
stack-based memory-allocation. I came up with the following idea which
resulted in a class I called the lallocator (derived from local alloca-
tor; this sounds funny in german because to "lall" means to babble in
german *g*).
First, we have the lallocator-class which is an interface to the locally
allocated storage for the stl-object (my lallocator can''t be used for
strings only). This class is the same for all sizes of local stack-based
pools to prevent that we would compile derived stl-classes for any size
we use. Second, there''s a class called lallocator_buffer_if which is the
interface to the local storage we allocated for the lallocator. I defined
this interface for all sizes of locally allocated pools to prevent any
secial-buffer-size-compiling I mentioned before. Third there''s a dervied
class of lallocator_buffer_if<T>, called lallocator_buffer<T, buffers,
size>; T is the usual data-type in the buffers, buffers is the number of
buffers which can be allocated by the lallocator and size is the size of
each buffer. Whenever someone tries to do an allocate() on the lallocator
and there''s a free buffer and the buffer is large enough to satisfy the
allocation-request, we''ll allocate the buffer from the pool; otherwise
we fall back to std::allocator.

Here''s an example of how this is used:

typedef std::basic_string<char, char_traits<char>, lallocator<char> >
lallostring;

lallocator_buffer<char, 5, 128> lbc;
lallocator<char> lallo( &lbc );
lallostring lsTest( lallo );

lsTest = "sdsdass";

Unfortunately my compiler isn''t able to eat the following code
to prevent explicit instanciation of a lallocator<T>-object:

lallocator_buffer<char, 5, 128> lbc;
lallostring lsTest( lallocator<char>( &lbc ) );

Does anyone know if there''s a conformance-problem here or is this
just a bug of my compiler?
So here''s my lalloator (it isn''t fully stl-conformant and I used a single
trick to prevent having an additional pointer in lallocator_buffer_if which
causes my code not to work on theoretical C++-implementations; sorry to all
religious developers):

template<typename T>
class lallocator_buffer_if
{
protected:
template<typename T, std::size_t buffers, std::size_t buffer_size>
friend class lallocator_buffer;

template<typename T>
friend class lallocator;

private:
lallocator_buffer_if() {}
T *pop_buffer();
void push_buffer( T *pt );
bool is_yours( T *pt );

protected:
union buffer_header
{
buffer_header *pbhNextFree;
T at[1];
};

protected:
std::size_t m_buffer_size;
buffer_header *m_pbhFirstFree;
buffer_header *m_pbhBufferEnd;
};

template<typename T>
inline
T *lallocator_buffer_if<T>::pop_buffer()
{
buffer_header *pbh;

if( (pbh = m_pbhFirstFree) == NULL )
return NULL;

return m_pbhFirstFree = pbh->pbhNextFree,
&pbh->at[0];
}
template<typename T>
inline
void lallocator_buffer_if<T>::push_buffer( T *pt )
{
buffer_header *pbh;

pbh = (buffer_header *)pt;
pbh->pbhNextFree = m_pbhFirstFree;
m_pbhFirstFree = pbh;
}

template<typename T>
inline
bool lallocator_buffer_if<T>::is_yours( T *pt )
{
return (void*)pt >= (void *)this &&
pt < &m_pbhBufferEnd->at[0];
}

template<typename T, std::size_t buffers, std::size_t buffer_size>
class lallocator_buffer : public lallocator_buffer_if<T>
{
public:
lallocator_buffer();

private:
union buffer
{
buffer_header bh;
T atUnReferenced[buffer_size];
};

private:
buffer aBuffers[buffers];
};

template<typename T, std::size_t buffers, std::size_t buffer_size>
inline
lallocator_buffer<T, buffers, buffer_size>::lallocator_buffer()
{
buffer *pbuf,
*pbufNext;

for( (pbuf = &aBuffers[buffers - 1],
pbufNext = NULL);
pbuf >= aBuffers;
(pbufNext = pbuf,
pbuf -= 1) )
pbuf->bh.pbhNextFree = &pbufNext->bh;

m_buffer_size = buffer_size;
m_pbhBufferEnd = &aBuffers[buffers].bh;
m_pbhFirstFree = &aBuffers[0].bh;
}

template<typename T>
class lallocator : public std::allocator<T>
{
public:
lallocator( lallocator_buffer_if<T> *plbi );
lallocator( lallocator const &lc );
~lallocator() {};
pointer allocate( size_type count, void *hint = NULL );
void deallocate( pointer ptr, size_type count );
lallocator &operator =( lallocator const &lc );

public:
template<class Other>
struct rebind
{
typedef lallocator<Other> other;
};

private:
lallocator_buffer_if<T> *m_plbi;
};

template<typename T>
inline
lallocator<T>::lallocator( lallocator_buffer_if<T> *plbi ) :
std::allocator<T>()
{
m_plbi = plbi;
}

template<typename T>
inline
lallocator<T>::lallocator( lallocator const &lc ) :
std::allocator<T>( lc )
{
m_plbi = lc.m_plbi;
}

template<typename T>
inline
typename lallocator<T>::pointer lallocator<T>::allocate( size_type count,
void *hint )
{
T *pt;

if( count > m_plbi->m_buffer_size ||
(pt = m_plbi->pop_buffer()) == NULL )
return std::allocator<T>::allocate( count );

return pt;
}

template<typename T>
inline
void lallocator<T>::deallocate( pointer ptr, size_type count )
{
if( !m_plbi->is_yours( ptr ) )
return (void)std::allocator<T>::deallocate( ptr, count );

m_plbi->push_buffer( ptr );
}

template<typename T>
inline
typename lallocator<T> &lallocator<T>::operator =( lallocator const &lc )
{
return m_plbi = lc.m_plbi,
*this;
}


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:st*****@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

推荐答案



Oliver S.写道:

Oliver S. wrote:
我经常对std :: basic-string的性能感到恼火,因为
复杂的内存分配器在后台运行找到了std :: allocator< T>的工作。基本上,在大多数情况下,性能并没有超过基于堆栈的C字符串的形成。但是,
舒适性和对缓冲区溢出的隐式保护使得std ::
basic_string值得使用。所以我搜索了一种方法来拥有自己的基于堆栈的内存分配。我提出了以下想法,它导致了一个叫做lallocator的课程(来自本地分配器;这在德语中听起来很有趣,因为lall意味着喋喋不休
german * g *)。
首先,我们有lallocator类,它是stl-object的本地分配存储的接口(我的lallocator不能用于
仅限字符串)。对于所有大小的本地基于堆栈的池,此类都是相同的,以防止我们编译任何大小的派生stl类,我们使用它们。其次,有一个名为lallocator_buffer_if的类,它是我们为lallocator分配的本地存储的接口。我为所有大小的本地分配的池定义了这个接口,以防止我之前提到的任何
secial-buffer-size-compiling。第三,有一种类型为lallocator_buffer_if< T>,称为lallocator_buffer< T,缓冲区,
尺寸> ;; T是缓冲区中常用的数据类型,缓冲区是可以由lallocator分配的缓冲区数,大小是每个缓冲区的大小。每当有人试图在lallocator上做一个allocate()并且有一个空闲缓冲区并且缓冲区足够大以满足
分配请求时,我们将从池中分配缓冲区;否则
我们回到std :: allocator。

这里有一个如何使用它的例子:

typedef std :: basic_string< char, char_traits< char> ;, lallocator< char> >
lallostring;

lallocator_buffer< char,5,128> lbc;
lallocator< char> lallo(& lbc);
lallostring lsTest(lallo);

lsTest =" sdsdass" ;;

不幸的是我的编译器无法进食以下代码用于防止lallocator的显式实例< T> -object:

lallocator_buffer< char,5,128> lbc;
lallostring lsTest(lallocator< char>(& lbc));

有谁知道这里是否存在一致性问题或者这只是一个bug我的编译器是什么?

所以这里是我的lalloator(它不是完全符合标准,我用了一个
技巧来防止在lallocator_buffer_if中有一个额外的指针
导致我的代码不能用于理论C ++ - 实现;对所有
宗教开发者抱歉:
...
I was often annoyed about the performance of std::basic-string because
of complex memory-allocators working in the background to found the work
of std::allocator<T>. Basically, the performance doesn''t reeach the per-
formance of a stack-based C-string in most cases. But nevertheless, the
comfort and the implicit protection against buffer-overflows makes std::
basic_string woth to be used. So I searched for a way to have my own
stack-based memory-allocation. I came up with the following idea which
resulted in a class I called the lallocator (derived from local alloca-
tor; this sounds funny in german because to "lall" means to babble in
german *g*).
First, we have the lallocator-class which is an interface to the locally
allocated storage for the stl-object (my lallocator can''t be used for
strings only). This class is the same for all sizes of local stack-based
pools to prevent that we would compile derived stl-classes for any size
we use. Second, there''s a class called lallocator_buffer_if which is the
interface to the local storage we allocated for the lallocator. I defined
this interface for all sizes of locally allocated pools to prevent any
secial-buffer-size-compiling I mentioned before. Third there''s a dervied
class of lallocator_buffer_if<T>, called lallocator_buffer<T, buffers,
size>; T is the usual data-type in the buffers, buffers is the number of
buffers which can be allocated by the lallocator and size is the size of
each buffer. Whenever someone tries to do an allocate() on the lallocator
and there''s a free buffer and the buffer is large enough to satisfy the
allocation-request, we''ll allocate the buffer from the pool; otherwise
we fall back to std::allocator.

Here''s an example of how this is used:

typedef std::basic_string<char, char_traits<char>, lallocator<char> >
lallostring;

lallocator_buffer<char, 5, 128> lbc;
lallocator<char> lallo( &lbc );
lallostring lsTest( lallo );

lsTest = "sdsdass";

Unfortunately my compiler isn''t able to eat the following code
to prevent explicit instanciation of a lallocator<T>-object:

lallocator_buffer<char, 5, 128> lbc;
lallostring lsTest( lallocator<char>( &lbc ) );

Does anyone know if there''s a conformance-problem here or is this
just a bug of my compiler?
So here''s my lalloator (it isn''t fully stl-conformant and I used a single
trick to prevent having an additional pointer in lallocator_buffer_if which
causes my code not to work on theoretical C++-implementations; sorry to all
religious developers):
...




实际上,缓冲区的并集和指向下一个空闲缓冲区的

指针没有任何问题。它遵循

内存池的标准设计 - 这是你已经实现的。有关内存池的另一个示例,请参阅boost'''pool"

库。


内存池最适合常量内存分配 - 而

std :: string分配的大小会有所不同。但由于std :: string经常使用
进行许多小分配,因此对于内存池块使用足够大的大小仍然可以获得一些好处。一个更有效的优化更有效的优化是将一个固定大小的字符缓冲区

数据成员添加到字符串类本身。通过这样做,std :: strings的性能

等于字符串的基于堆栈的字符串

短于一定长度。

Greg

[见 http: //www.gotw.ca/resources/clcm.htm 了解有关的信息]

[comp.lang.c ++。moderated。第一次海报:做到这一点! ]


[comp.std.c ++被审核。要提交文章,请尝试发布]

[您的新闻阅读器。如果失败,请使用mailto:st ***** @ ncar.ucar.edu]

[---请在发布前查看常见问题解答。 ---]

[常见问题: http://www.jamesd.demon.co.uk/csc/faq.html ]



Actually, there is nothing wrong with the union of the buffer and the
pointer to the next free buffer. It follows the standard design for a
memory pool - which is what you have implemented. See boost''s "pool"
library for another example of a memory pool.

Memory pools work best for constant sized memory allocations - while
std::string allocations will vary in size. But since std::string often
makes many small allocations, there can still be some benefit from
using a sufficiently large size for the memory pool blocks. An even
more effective optimization would to add a fixed-sized character buffer
data member to the string class itself. By so doing, the performance
for std::strings would equal that of stack-based strings for strings
shorter than a certain length.

Greg
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:st*****@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]




Oliver S.写道:

Oliver S. wrote:
我经常对std :: basic-string的性能感到恼火,因为复杂的内存分配器在后台工作以找到工作 std :: allocator< T>。基本上,在大多数情况下,性能并没有超过基于堆栈的C字符串的形成。但是,
舒适性和对缓冲区溢出的隐式保护使得std ::
basic_string值得使用。所以我搜索了一种方法来拥有自己的基于堆栈的内存分配。我提出了以下想法,它导致了一个叫做lallocator的课程(来自本地分配器;这在德语中听起来很有趣,因为lall意味着喋喋不休
德语* g *)。


这是一个如何使用它的例子:

typedef std :: basic_string< char,char_traits< char> ;, lallocator< char> >
lallostring;

lallocator_buffer< char,5,128> lbc;
lallocator< char> lallo(& lbc);
lallostring lsTest(lallo);

lsTest =" sdsdass" ;;

不幸的是我的编译器无法进食以下代码用于防止lallocator的显式实例< T> -object:

lallocator_buffer< char,5,128> lbc;
lallostring lsTest(lallocator< char>(& lbc));


哦,这只是你声明功能的常见错误。


模板< typename T>
类lallocator:public std :: allocator< T>
{
公开:
lallocator(lallocator_buffer_if< T> * plbi);
lallocator(lallocator const& lc);
~lallocator (){};
指针分配(size_type count,void * hint = NULL);
void deallocate(指针ptr,size_type计数);
lallocator& operator =(lallocator const& lc);

公开:
模板< class其他>
struct rebind
{
typedef lallocator< Other>私人:
lallocator_buffer_if< T> * m_plbi;
};
I was often annoyed about the performance of std::basic-string because
of complex memory-allocators working in the background to found the work
of std::allocator<T>. Basically, the performance doesn''t reeach the per-
formance of a stack-based C-string in most cases. But nevertheless, the
comfort and the implicit protection against buffer-overflows makes std::
basic_string woth to be used. So I searched for a way to have my own
stack-based memory-allocation. I came up with the following idea which
resulted in a class I called the lallocator (derived from local alloca-
tor; this sounds funny in german because to "lall" means to babble in
german *g*).

Here''s an example of how this is used:

typedef std::basic_string<char, char_traits<char>, lallocator<char> >
lallostring;

lallocator_buffer<char, 5, 128> lbc;
lallocator<char> lallo( &lbc );
lallostring lsTest( lallo );

lsTest = "sdsdass";

Unfortunately my compiler isn''t able to eat the following code
to prevent explicit instanciation of a lallocator<T>-object:

lallocator_buffer<char, 5, 128> lbc;
lallostring lsTest( lallocator<char>( &lbc ) );
Oh, this is just common error you have declared function.


template<typename T>
class lallocator : public std::allocator<T>
{
public:
lallocator( lallocator_buffer_if<T> *plbi );
lallocator( lallocator const &lc );
~lallocator() {};
pointer allocate( size_type count, void *hint = NULL );
void deallocate( pointer ptr, size_type count );
lallocator &operator =( lallocator const &lc );

public:
template<class Other>
struct rebind
{
typedef lallocator<Other> other;
};

private:
lallocator_buffer_if<T> *m_plbi;
};




此类需要默认构造函数才能重新绑定。

好​​了,在更正编译器错误后,这里是你的代码:

你可以将静态指针用作默认构造函数,如果需要,可以将
转换成静态线程本地存储指针。

总有可能性分配给

的内存可以用其他分配器释放,所以你要小心不要在范围内设置不同的缓冲区。

#include< string>

#include< cassert>

//使用命名空间std;

#ifndef __GNUG__

#define __thread / * this_would_be_a_great_thing_to_have * /

#endif

模板< typename T>

class lallocator_buffer_if

{

受保护:

模板< typename TT,std :: size_t buffers,std :: size_t buffer_size>

朋友班lallocator_buffer;


模板< ; typename TT>

朋友类lallocator;


私人:

lallocator_buffer_if(){}

T * pop_buffer();

void push_buffer(T * pt);

bool is_yours(T * pt);


受保护:

union buffer_header

{

buffer_header * pbhNextFree;

T at [1];

};


受保护:

std :: size_t m_buffer_size;

buffer_header * m_pbhFirstFree;

buffer_header * m_pbhBufferEnd;


};


模板< typename T>

inline

T * lallocator_buffer_if< T> :: pop_buffer()

{

buffer_header * pbh;


if((pbh = m_pbhFirstFree)== NULL)

返回NULL;


返回m_pbhFirstFree = pbh-> pbhNextFree,

& pbh-> at [0];


}


模板< typename T>

inline

void lalloc ator_buffer_if< T> :: push_buffer(T * pt)

{

buffer_header * pbh;


pbh =(buffer_header * )pt;

pbh-> pbhNextFree = m_pbhFirstFree;

m_pbhFirstFree = pbh;


}


模板< typename T>

inline

bool lallocator_buffer_if< T> :: is_yours(T * pt)

{

return(void *)pt> =(void *)this&&

pt< & m_pbhBufferEnd-> at [0];


}


模板< typename T,std :: size_t buffers,std :: size_t buffer_size>

class lallocator_buffer:public lallocator_buffer_if< T>

{

public:

lallocator_buffer();


私人:

联盟缓冲区

{

typename lallocator_buffer_if< T> :: buffer_header bh ;

T atUnReferenced [buffer_size];

};


private:

buffer aBuffers [缓冲区];


};


模板< typename T,std :: size_t buffers,std :: size_t buffer_size>

inline

lallocator_buffer< T,buffers,buffer_size> :: lallocator_buffer()

{

buffer * pbuf,
* pbufNext;


for((pbuf =& aBuffers [buffers - 1],

pbufNext = NULL);

pbuf> = aBuffers;

(pbufNext = pbuf,

pbuf - = 1))

pbuf-> bh.pbhNextFree =& pbufNext-> bh;


this-> m_buffer_size = buffer_size;

this-> m_pbhBufferEnd =& aBuffers [buffers] .bh;

this-> m_pbhFirstFree =& aBuffers [0] .bh;


}


模板< typename T>

类lallocator:public std :: allocator< T>

{

public:

typedef typename std :: allocator< T> ::指针指针;

typedef typename std :: allocator< T> :: size_type size_type;

lallocator():m_plbi(m_buffer){assert(m_plbi); }

lallocator(lallocator_buffer_if< T> * plbi);

lallocator(lallocator const& lc);

~lallocator(){} ;

指针分配(size_type count,void * hint = NULL);

void deallocate(指针ptr,size_type计数);

lallocator& ; operator =(lallocator const& lc);


static void set_buffer(lallocator_buffer_if< T> * b)

{

m_buffer = b;

}


public:

template< class Other>

struct重新绑定

{

typedef lallocator< Other>其他;

};


私人:

lallocator_buffer_if< T> * m_plbi;

静态__thread lallocator_buffer_if< T> * m_buffer;

};


模板< typename T>

__thread lallocator_buffer_if< T> * lallocator< T> :: m_buffer = 0;


模板< typename T>

inline

lallocator< T> :: lallocator(lallocator_buffer_if< T> * plbi):

std :: allocator< T>()

{

m_plbi = plbi;


}


模板< typename T>

inline

lallocator< T> :: lallocator(lallocator const& lc):

std :: allocator< T>(lc)

{

m_plbi = lc.m_plbi;


}


模板< typename T>

inline

typename lallocator< T> :: pointer lallocator< T> :: allocate(size_type

count,void * hint)

{

T * pt;


if(count> m_plbi-> m_buffer_size ||

(pt = m_p lbi-> pop_buffer())== NULL)

返回std :: allocator< T> :: allocate(count);


return pt;


}


模板< typename T>

inline

void lallocator< T> :: deallocate(指针ptr,size_type计数)

{

if(!m_plbi-> is_yours(ptr))

return (void)std :: allocator< T> :: deallocate(ptr,count);


m_plbi-> push_buffer(ptr);


}


模板< typename T>

inline

lallocator< T>& lallocator< T> :: operator =(lallocator< T> const& lc)

{

返回m_plbi = lc.m_plbi,

*这个;


}


int main()

{

typedef std :: basic_string< char,std :: char_traits< char>,

lallocator< char> >

lallostring;


lallocator_buffer< char,5,128> lbc;

lallocator< char> lallo(& lbc);

lallocator< char> :: set_buffer(& lbc);

lallostring lsTest(lallo);


lsTest =" sdsdass";

{

lallocator_buffer< char,5,128> lbc;

lallocator< char> :: set_buffer(& lbc);

lallostring lsTest((lallocator< char>(& lbc

)));

lsTest + =" abc" + lallostring(" def");

}

}


问候,Bane。

[见 http://www.gotw.ca/resources/clcm.htm 有关的信息]

[comp.lang.c ++。moderated。第一次海报:做到这一点! ]


[comp.std.c ++被审核。要提交文章,请尝试发布]

[您的新闻阅读器。如果失败,请使用mailto:st ***** @ ncar.ucar.edu]

[---请在发布前查看常见问题解答。 ---]

[常见问题: http://www.jamesd.demon.co.uk/csc/faq.html ]



This class needs default constructor for rebind purposes.
Ok, after correcting compiler errors here is your code:
you can make static pointer used for default constructor,
into a static thread local storage pointer if needed.
There is alwayspossibility that memory allocated with
one allocator could be freed with other, so you have
to be carefull not to set different buffers in a scope.

#include <string>
#include <cassert>
//using namespace std;
#ifndef __GNUG__
#define __thread /* this_would_be_a_great_thing_to_have */
#endif
template<typename T>
class lallocator_buffer_if
{
protected:
template<typename TT, std::size_t buffers, std::size_t buffer_size>
friend class lallocator_buffer;

template<typename TT>
friend class lallocator;

private:
lallocator_buffer_if() {}
T *pop_buffer();
void push_buffer( T *pt );
bool is_yours( T *pt );

protected:
union buffer_header
{
buffer_header *pbhNextFree;
T at[1];
};

protected:
std::size_t m_buffer_size;
buffer_header *m_pbhFirstFree;
buffer_header *m_pbhBufferEnd;

};

template<typename T>
inline
T *lallocator_buffer_if<T>::pop_buffer()
{
buffer_header *pbh;

if( (pbh = m_pbhFirstFree) == NULL )
return NULL;

return m_pbhFirstFree = pbh->pbhNextFree,
&pbh->at[0];

}

template<typename T>
inline
void lallocator_buffer_if<T>::push_buffer( T *pt )
{
buffer_header *pbh;

pbh = (buffer_header *)pt;
pbh->pbhNextFree = m_pbhFirstFree;
m_pbhFirstFree = pbh;

}

template<typename T>
inline
bool lallocator_buffer_if<T>::is_yours( T *pt )
{
return (void*)pt >= (void *)this &&
pt < &m_pbhBufferEnd->at[0];

}

template<typename T, std::size_t buffers, std::size_t buffer_size>
class lallocator_buffer : public lallocator_buffer_if<T>
{
public:
lallocator_buffer();

private:
union buffer
{
typename lallocator_buffer_if<T>::buffer_header bh;
T atUnReferenced[buffer_size];
};

private:
buffer aBuffers[buffers];

};

template<typename T, std::size_t buffers, std::size_t buffer_size>
inline
lallocator_buffer<T, buffers, buffer_size>::lallocator_buffer()
{
buffer *pbuf,
*pbufNext;

for( (pbuf = &aBuffers[buffers - 1],
pbufNext = NULL);
pbuf >= aBuffers;
(pbufNext = pbuf,
pbuf -= 1) )
pbuf->bh.pbhNextFree = &pbufNext->bh;

this->m_buffer_size = buffer_size;
this->m_pbhBufferEnd = &aBuffers[buffers].bh;
this->m_pbhFirstFree = &aBuffers[0].bh;

}

template<typename T>
class lallocator : public std::allocator<T>
{
public:
typedef typename std::allocator<T>::pointer pointer;
typedef typename std::allocator<T>::size_type size_type;
lallocator():m_plbi(m_buffer) { assert(m_plbi); }
lallocator( lallocator_buffer_if<T> *plbi );
lallocator( lallocator const &lc );
~lallocator() {};
pointer allocate(size_type count, void *hint = NULL );
void deallocate( pointer ptr, size_type count );
lallocator &operator =( lallocator const &lc );

static void set_buffer(lallocator_buffer_if<T>* b)
{
m_buffer=b;
}

public:
template<class Other>
struct rebind
{
typedef lallocator<Other> other;
};

private:
lallocator_buffer_if<T> *m_plbi;
static __thread lallocator_buffer_if<T>* m_buffer;
};

template <typename T>
__thread lallocator_buffer_if<T>* lallocator<T>::m_buffer=0;

template<typename T>
inline
lallocator<T>::lallocator( lallocator_buffer_if<T> *plbi ):
std::allocator<T>()
{
m_plbi = plbi;

}

template<typename T>
inline
lallocator<T>::lallocator( lallocator const &lc ) :
std::allocator<T>( lc )
{
m_plbi = lc.m_plbi;

}

template<typename T>
inline
typename lallocator<T>::pointer lallocator<T>::allocate( size_type
count, void *hint )
{
T *pt;

if( count > m_plbi->m_buffer_size ||
(pt = m_plbi->pop_buffer()) == NULL )
return std::allocator<T>::allocate( count );

return pt;

}

template<typename T>
inline
void lallocator<T>::deallocate( pointer ptr, size_type count )
{
if( !m_plbi->is_yours( ptr ) )
return (void)std::allocator<T>::deallocate( ptr, count );

m_plbi->push_buffer( ptr );

}

template<typename T>
inline
lallocator<T>& lallocator<T>::operator =( lallocator<T> const &lc )
{
return m_plbi = lc.m_plbi,
*this;

}

int main()
{
typedef std::basic_string<char, std::char_traits<char>,
lallocator<char> >
lallostring;

lallocator_buffer<char, 5, 128> lbc;
lallocator<char> lallo( &lbc );
lallocator<char>::set_buffer(&lbc);
lallostring lsTest( lallo );

lsTest = "sdsdass";
{
lallocator_buffer<char, 5, 128> lbc;
lallocator<char>::set_buffer(&lbc);
lallostring lsTest ((lallocator<char>( &lbc
)));
lsTest+="abc"+lallostring("def");
}
}

Greetings, Bane.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:st*****@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]




Oliver S.写道:

...

Oliver S. wrote:
...
不幸的是我的编译器无法吃下面的代码


那不是很具体。如果你指出

,那么你的编译器说这个代码是难以理解的,这会有很大的帮助。


...所以这里''我的lalloator(它不是完全符合标准,我使用了一个单一的技巧来防止在lallocator_buffer_if中有一个额外的指针,这会导致我的代码不能用于理论C ++ - 实现;对不起
宗教开发者):
Unfortunately my compiler isn''t able to eat the following code
That isn''t very specific. It would help a great deal if you indicated
what, precisely, your compiler said was indigestible about this code.

... So here''s my lalloator (it isn''t fully stl-conformant and I used a single
trick to prevent having an additional pointer in lallocator_buffer_if which
causes my code not to work on theoretical C++-implementations; sorry to all
religious developers):




您使用的词语理论和宗教的意味着你认为不合格是不重要的。有可能;但你应该认真考虑你所遇到的问题可能实际上是因为不合格而导致的b $ b。特别是,允许​​实现

假设给定分配器类型的所有实例都相当于
(20.1.5p4),这对于你的分配器来说并非如此。虽然

标准鼓励实现者创建实现,但是b
不依赖于这个假设,其中许多实际上确实利用了

该选项,例如,实际上没有复制分配器时

它们具有相同的类型。


std :: list< T,Allocator> :: splice ()特别难以有效地实施

,除非你假设所有

分配器的实例都是等价的。

[见 http://www.gotw.ca/resources/clcm.htm for info about

[comp.lang.c ++。moderated。第一次海报:做到这一点! ]


[comp.std.c ++被审核。要提交文章,请尝试发布]

[您的新闻阅读器。如果失败,请使用mailto:st ***** @ ncar.ucar.edu]

[---请在发布前查看常见问题解答。 ---]

[常见问题: http://www.jamesd.demon.co.uk/csc/faq.html ]



Your use of the words "theoretical" and "religious" implies that you
think the non-conformance is unimportant. It might be; but you should
seriously consider the possibility that the problems you''re having may
in fact be due to that non-conformance. In particular, implementations
are allowed to assume that all instances of a given allocator type are
equivalent (20.1.5p4), which isn''t the case for your allocators. While
the standard encourages implementators to create implementations that
don''t rely on that assumption, many of them do in fact take advantage
of that option, for instance by not actually copying allocators when
they have the same type.

std::list<T,Allocator>::splice() is particularly difficult to implement
efficiently unless you build in an assumption that all instances of
Allocator are equivalent.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:st*****@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]


这篇关于我的lallocator&lt; T&gt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆