问题描述:
1.vector是最常用到的容器,它其实是一种自动扩充的动态数组,底层实现通过两倍扩展,
所以再不能预知要存入元素多少时,难免要两倍扩展,这带来了拷贝所存对象的开销;
2.本文尝试利用memory chunk作为底层存储容器来避免动态扩展时copy 开销;
3.本实现屏蔽了STL vector 一些接口比如erase,主要是为了减轻实现复杂性考虑;
4.它支持两边插入和删除操作,其接口功能完全等同于STL 的deque;
5.和STL vector 做了push_back, pop_back, at 操作性能比较,结果如下:
1)push_back 操作,性能改善了4-5倍;
2)at操作,基本上相当;
3)pop_back性能变慢了3-4倍;
4) 尽管pop_back性能变慢了,但是我的实现内存大小是可伸缩的;
程序代码:
#ifndef _ALVECTOR_H_
#define _ALVECTOR_H_
#include <vector>
#include "windows.h"
/*
* the class encapsulate dynamic array the same as STL vector from function
* it have different underlying storage with STL vector
* it apply to memory chunk tech linked the chunk by next point
* it have good insert performance because no copy burden when full storage
*
*/
template<class T>
class AlVector
{
public:
/*
* memory chunk(storage chunk) for interval using
*
*/
enum
{
KSlotCount = 64
};
int m_totalCount;
int m_count;
struct Buffer
{
T buf[KSlotCount];
Buffer* next;
Buffer():next(0)
{
memset( buf, 0x00, sizeof(buf) );
}
};
/*
* Constructor
*
*/
AlVector():m_totalCount(0), m_count(0),
m_chunkHead(0), m_chunkSize(0),
m_chunkCapacity(0)
{
InitChunkIndex();
m_dataBuffer = &m_initBuffer;
AssignChunkIndex( m_dataBuffer );
}
/*
* Copy Constructor
*
*/
AlVector( const AlVector& rhs )
{
size_t len = rhs.Size();
for( size_t i = 0; i < len; i++ )
this->PushBack( rhs[i] );
}
/*
* Assignment operator overload
*
*/
AlVector& operator = ( const AlVector& rhs )
{
if( this != &rhs )
{
Clear();
size_t len = rhs.Size();
for( size_t i = 0; i < len; i++ )
this->PushBack( rhs[i] );
}
return *this;
}
/*
* Destructor
*
*/
~AlVector()
{
Clear();
}
/*
*
*
*/
T& operator [] ( size_t index )
{
return At( index );
}
/*
*
*
*/
const T& operator[] ( size_t index ) const
{
return At( index );
}
/*
* Check whether or not exist element
*
*/
bool IsEmpty()
{
return m_totalCount == 0;
}
/*
* Retrieve the number of elements in container
*
*/
size_t Size() const
{
return m_totalCount;
}
/*
* Clear all object pushed and memory
*
*/
void Clear()
{
while( m_dataBuffer != &m_initBuffer )
{
Buffer* buf = m_dataBuffer;
m_dataBuffer = m_dataBuffer->next;
delete buf;
}
delete [] m_chunkHead;
m_chunkHead = 0;
m_chunkSize = m_chunkCapacity = 0;
}
/*
* Push element to container tail
*
*/
void PushBack( const T& data )
{
*Push() = data;
}
/*
* Pop element from container tail
*
*/
void PopBack()
{
m_totalCount--;
if( --m_count == 0 )
{
if( m_dataBuffer != &m_initBuffer )
{
Buffer* buf = m_dataBuffer;
m_dataBuffer = m_dataBuffer->next;
//important
m_chunkHead[m_chunkSize] = 0;
m_chunkSize--;
delete buf;
buf = 0;
// reset the value of m_count
m_count = KSlotCount;
}
}
}
/*
* Retrieve the element of header in container
*
*/
T& Front()
{
return m_chunkHead[0]->buf[0];
}
/*
* Retrieve the element of header in container
*
*/
const T& Front() const
{
return Front();
}
/*
* Retrieve the element of tail in container
*
*/
T& Back()
{
return Back()
}
/*
* Retrieve the element of tail in container
*
*/
const T& Back() const
{
assert( m_count > 0 );
return m_dataBuffer[ m_count - 1 ];
}
/*
* Retrieve the element by terms of position index
*
*/
T& At( size_t index )
{
assert( index < m_totalCount );
if( index < KSlotCount )
return m_initBuffer.buf[index];
return m_chunkHead[index / KSlotCount]->buf[index % KSlotCount];
}
/*
* Retrieve the element by terms of position index
*
*/
const T& At( size_t index ) const
{
assert( index < m_totalCount );
if( index < KSlotCount )
return m_initBuffer.buf[index];
return m_chunkHead[index / KSlotCount]->buf[index % KSlotCount];
}
protected:
/*
*
*
*/
T* Push()
{
if( KSlotCount == m_count )
{
Buffer* buf = new Buffer;
assert( buf );
buf->next = m_dataBuffer;
m_dataBuffer = buf;
//important
AssignChunkIndex( buf );
//reset the value of value in single buffer
m_count = 0;
}
m_totalCount++;
return &m_dataBuffer->buf[m_count++];
}
/*
* Init the array of index of buffer pointer
*
*/
void InitChunkIndex()
{
m_chunkCapacity = KSlotCount;
m_chunkHead = new Buffer*[m_chunkCapacity];
memset( m_chunkHead, 0x00, sizeof(Buffer*)* m_chunkCapacity );
m_chunkSize;
}
/*
* Store currently buffer pointer to array of index
*
*/
void AssignChunkIndex( Buffer* curBuffer )
{
if( m_chunkSize >= m_chunkCapacity )
{
m_chunkCapacity += 2;// important
m_chunkCapacity <<= 1;
Buffer** newHead = new Buffer*[ m_chunkCapacity ];
memset( newHead, 0x00, sizeof(Buffer*)* m_chunkCapacity );
if( m_chunkHead )
{
memcpy( newHead, m_chunkHead, sizeof(Buffer*) * m_chunkSize );
delete [] m_chunkHead;
}
m_chunkHead = newHead;
}
m_chunkHead[m_chunkSize++] = curBuffer;
}
protected:
Buffer m_initBuffer; // static storage for a small amount object operation
Buffer* m_dataBuffer; // currently the pointer of buffer of storage
Buffer** m_chunkHead; // the array of index of buffer of storage allocated
size_t m_chunkSize; // the length of array of index of buffer
size_t m_chunkCapacity; // the capacity of ...
};
/*
* Test STL vector
*
*/
void TestSTLVector()
{
std::vector<int> stlVec;
int len = 64 * 100000;
printf("STL Vector test result : \n " );
unsigned long start= GetTickCount();
for( int i = 0; i < len; i++ )
{
stlVec.push_back( i );
}
unsigned long interval = GetTickCount() - start;
printf( "insert operation consume time is %d in STL vector\n", interval );
start= GetTickCount();
for( int i = 0; i < len; i++ )
{
assert( stlVec[i] == i );
}
interval = GetTickCount() - start;
printf( "retrieve operation consume time is %d in STL vector\n", interval );
start= GetTickCount();
for( int i = 0; i < len; i++ )
{
stlVec.pop_back();
}
interval = GetTickCount() - start;
printf( "pop operation consume time is %d in STL vector\n", interval );
assert( stlVec.size() == 0 );
}
/*
* Test AlVector
*
*/
void TestVector()
{
int len = 64 * 100000;
AlVector<int> vecObj;
printf("AlVector Vector test result : \n " );
unsigned long start= GetTickCount();
for( int i = 0; i < len; i++ )
{
vecObj.PushBack( i );
}
unsigned long interval = GetTickCount() - start;
printf( "insert operation consume time is %d in AlVector \n", interval );
start= GetTickCount();
for( int i = 0; i < len; i++ )
{
assert( vecObj[i] == i );
}
interval = GetTickCount() - start;
printf( "retrieve operation consume time is %d in AlVector\n", interval );
start= GetTickCount();
for( int i = 0; i < len; i++ )
{
vecObj.PopBack();
}
interval = GetTickCount() - start;
printf( "pop operation consume time is %d in AlVector\n", interval );
assert( vecObj.Size() == 0 );
vecObj.Clear();
}
/*
* Test interface
*
*/
void TestVectorSuite()
{
TestVector();
TestSTLVector();
}
#endif
compile and run in visual studio 2005
test result as follows: