首页 > 代码库 > 利用内存chunk充当数据buffer的vector的实现,和STL vector 有接口操作性能比较
利用内存chunk充当数据buffer的vector的实现,和STL vector 有接口操作性能比较
问题描述:
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:
利用内存chunk充当数据buffer的vector的实现,和STL vector 有接口操作性能比较
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。