vector是STL里最常用的容器,本文尝试着用一种相对简单的方法构建一个vector实现模板,并加上std::allocator。尽可能解释其中函数的意义。
用一个testAllocator继承allocator。此处特化int版本。
#ifndef __TEST_H__
#define __TEST_H__
#include <memory>
#include <iostream>
class testAllocator : public std::allocator<int> {
public:
typedef std::allocator<int> Base;
// 此函数就是new功能。真正分配内存。
int * allocate(std::size_t size) {
std::cout << "Test Allocator: allocate" << std::endl;
return Base::allocate(size);
}
// delete功能。真正释放内存。
void deallocate(int * p, std::size_t size) {
std::cout << "Test Allocator: deallocate" << std::endl;
Base::deallocate(p, size);
}
// 此函数不释放内存,只赋值。
void construct(int * p, int val) {
std::cout << "Test Allocator: Construct, value: " << val
<< std::endl;
Base::construct(p, val);
}
// 此函数不释放内存,只把值丢去。
void destroy(int * p) {
std::cout << "Test Allocator: Destroy, value: " << *p << std::endl;
Base::destroy(p);
}
};
#endif
#ifndef __VECTOR_H__
#define __VECTOR_H__
#define _a Alloc()
#include "base.h"
#include <memory>
template< typename T, typename Alloc = std::allocator<T> >
class myVector : public Base {
public:
// Constructor
myVector() {
_data = _a.allocate(1);
_size = 0;
_capacity = 1;
}
myVector(const std::size_t & size, const T & val,
Alloc a = Alloc()) {
_data = a.allocate(size);
for (std::size_t i = 0; i < size; ++i)
a.construct(_data + i, val);
_size = _capacity = size;
}
template<typename InputIterator>
myVector(InputIterator begin, InputIterator end,
Alloc a = Alloc()) {
_size = _capacity = end - begin;
_data = a.allocate(_size);
std::size_t cnt = 0;
for (InputIterator it = begin; it != end; ++it)
a.construct(_data + (cnt++), *it);
}
myVector(const myVector & other) {
_size = other._size;
_capacity = other._capacity;
_data = _a.allocate(_capacity);
for (std::size_t i = 0; i < _size; ++i)
_a.construct(_data + i, other._data[i]);
}
// Destructor
~myVector() {
for (std::size_t i = 0; i < _size; ++i)
_a.destroy(_data + i);
if (_capacity > 0)
_a.deallocate(_data, _capacity);
}
// Copy Operator
myVector & operator=(const myVector & other) {
if (&other != this) {
std::size_t i;
for (i = 0; i < _size; ++i)
_a.destroy(_data + i);
if (_capacity > 0)
_a.deallocate(_data, _capacity);
_size = other._size;
_capacity = other._capacity;
_data = _a.allocate(_capacity);
for (i = 0; i < _size; ++i)
_a.construct(_data + i, other._data[i]);
}
return *this;
}
// Iterator
typedef T * iterator;
typedef const T * const_iterator;
inline iterator begin() {
return _data;
}
inline const_iterator begin() const {
return _data;
}
inline iterator end() {
return _data + _size;
}
inline const_iterator end() const {
return _data + _size;
}
// Capacity
inline std::size_t size() const {
return _size;
}
void resize(const std::size_t & newSize) {
std::size_t i;
if (newSize <= _size) {
for (i = newSize; i < _size; ++i)
_a.destroy(_data + i);
} else {
if (newSize > _capacity) {
std::size_t newCapacity = _capacity * 2;
while (newSize > newCapacity)
newCapacity *= 2;
reserve(newCapacity);
}
for (i = _size; i < newSize; ++i)
_a.construct(_data + i, T());
}
_size = newSize;
}
void resize(const std::size_t & newSize, const T & val) {
std::size_t i;
if (newSize <= _size) {
for (i = newSize; i < _size; ++i)
_a.destroy(_data + i);
} else {
if (newSize > _capacity) {
std::size_t newCapacity = _capacity * 2;
while (newSize > newCapacity)
newCapacity *= 2;
reserve(newCapacity);
}
for (i = _size; i < newSize; ++i)
_a.construct(_data + i, val);
}
_size = newSize;
}
inline std::size_t capacity() const {
return _capacity;
}
inline bool empty() const {
return _size == 0;
}
void reserve(const std::size_t & newCapacity) {
if (newCapacity > _capacity) {
T * temp = _a.allocate(newCapacity);
for (std::size_t i = 0; i < _size; ++i) {
_a.construct(temp + i, _data[i]);
_a.destroy(_data + i);
}
_a.deallocate(_data, _capacity);
_capacity = newCapacity;
_data = temp;
}
}
// Element Access
inline T & operator[](const std::size_t & index) {
return _data[index];
}
inline const T & operator[](const std::size_t & index) const {
return _data[index];
}
inline T & front() {
return _data[0];
}
inline const T & front() const {
return _data[0];
}
inline T & back() {
return _data[_size - 1];
}
inline const T & back() const {
return _data[_size - 1];
}
inline T * data() {
return _data;
}
inline const T * data() const {
return _data;
}
// Modifiers
template<typename InputIterator>
void assign(InputIterator begin, InputIterator end) {
std:size_t newSize = 0;
InputIterator it;
for (it = begin; it != end; ++it)
++newSize;
if (newSize > _capacity) {
std::size_t newCapacity = _capacity * 2;
while (newSize > newCapacity)
newCapacity *= 2;
reserve(newCapacity);
}
std::size_t i;
for (i = 0; i < _size; ++i)
_a.destroy(_data + i);
for (i = 0, it = begin; i < newSize; ++i, ++it)
_a.construct(_data + i, *it);
_size = newSize;
}
void assign(const std::size_t & newSize, const T & val) {
if (newSize > _capacity) {
std::size_t newCapacity = _capacity * 2;
while (newSize > newCapacity)
newCapacity *= 2;
reserve(newCapacity);
}
std::size_t i;
for (i = 0; i < _size; ++i)
_a.destroy(_data + i);
for (i = 0; i < newSize; ++i)
_a.construct(_data + i, val);
_size = newSize;
}
void push_back(const T & val) {
if (_size >= _capacity)
reserve(_capacity * 2);
_a.construct(_data + (_size++), val);
}
void pop_back() {
_a.destroy(_data + (--_size));
}
void clear() {
for (std::size_t i = 0; i < _size; ++i)
_a.destroy(_data + i);
_size = 0;
}
private:
iterator _data;
std::size_t _size, _capacity;
};
#endif
#ifndef __BASE_H__
#define __BASE_H__
// #define vector NOT_ALLOWED
#define define NOT_ALLOWED
class Base {};
#endif
#include <iostream>
#include "test.h"
#include "base.h"
#include "vector.h"
int main() {
typedef myVector<int, testAllocator> v;
Base * test = new v;
delete static_cast<v *>(test);
v * p1, * p2;
int t;
std::cout << "Test Constructor1:" << std::endl;
p1 = new v;
std::cout << "Size: " << p1->size() << std::endl;
delete p1;
std::cout << "Test Constructor2 and operator[]:" << std::endl;
p1 = new v(static_cast<std::size_t>(6), 6);
std::cout << "Size: " << p1->size() << std::endl;
std::cout << "Content:";
for (int i = 0; i < 2; ++i)
std::cout << ' ' << (*p1)[i];
std::cout << std::endl;
std::cin >> t;
std::cout << "Content after change:";
(*p1)[0] = t;
const v & r(*p1);
for (int i = 0; i < 2; ++i)
std::cout << ' ' << r[i];
std::cout << std::endl;
std::cout << "Test Constructor3 and iterators, including begin(), end():"
<< std::endl;
p2 = new v(r.begin(), r.end());
delete p1;
std::cout << "Content:";
for (v::iterator it = p2->begin(); it != p2->end(); ++it)
std::cout << ' ' << *it;
std::cout << std::endl;
std::cout << "Test Constructor4:" << std::endl;
*(p2->begin()) = 0;
p1 = new v(*p2);
delete p2;
std::cout << "Content:";
for (std::size_t i = 0; i < p1->size(); ++i)
std::cout << ' ' << (*p1)[i];
std::cout << std::endl;
std::cout << "Test operator=:" << std::endl;
p2 = new v(static_cast<std::size_t>(8), 8);
*p2 = *p1;
*p2 = *p2;
delete p1;
std::cout << "Content:";
for (std::size_t i = 0; i < p2->size(); ++i)
std::cout << ' ' << (*p2)[i];
std::cout << std::endl;
std::cout << "Test resize1:" << std::endl;
p2->resize(2);
std::cout << "Content:";
for (std::size_t i = 0; i < p2->size(); ++i)
std::cout << ' ' << (*p2)[i];
std::cout << std::endl;
std::cout << "Test resize2:" << std::endl;
p2->resize(8, 8);
std::cout << "Content:";
for (std::size_t i = 0; i < p2->size(); ++i)
std::cout << ' ' << (*p2)[i];
std::cout << std::endl;
std::cout << "Test reserve and capacity:" << std::endl;
p2->reserve(33);
std::cout << "Capacity: " << p2->capacity() << std::endl
<< "Size: " << p2->size() << std::endl;
p2->reserve(2);
std::cout << "Capacity: " << p2->capacity() << std::endl
<< "Size: " << p2->size() << std::endl;
std::cout << "Test clear and empty:" << std::endl;
if (p2->empty())
std::cout << "True" << std::endl;
else
std::cout << "False" << std::endl;
p2->clear();
if (p2->empty())
std::cout << "True" << std::endl;
else
std::cout << "False" << std::endl;
std::cout << "Capcaity: " << p2->capacity() << std::endl
<< "Size: " << p2->size() << std::endl;
int * arr = new int[5];
for (int i = 0; i < 5; ++i)
arr[i] = i+1;
std::cout << "Test assign:" << std::endl;
p2->assign(arr, arr+5);
std::cout << "Content:";
for (v::const_iterator it = p2->begin(); it != p2->end(); ++it)
std::cout << ' ' << *it;
std::cout << std::endl << "Size: " << p2->size()
<< std::endl << "Capacity: " << p2->capacity()
<< std::endl;
delete [] arr;
delete p2;
return 0;
}