C++STL本身已经继承到很多模板,例如:向量模板:vector, list… 关联式容器: set, map等等。最近关于向量容器,自己动手实现了一下类似向量容器vector的一个简单实现。话不多说,直接上代码。
#ifndef _MYVECTOR_H
#define _MYVECTOR_H
#include<iostream>
#include<memory>
#include<utility>
template <typename T>
class myVector {
typedef T value_type;
typedef T* iterator;
typedef const T* const_iterator;
typedef T& reference;
template <typename U> friend std::ostream &operator<<(std::ostream&, const myVector<U>&);
private:
iterator _elements;
iterator memory_free;
iterator _capacity;
std::allocator<value_type> alloc; //myVector allocator
std::pair<iterator, iterator> alloc_n_copy(const_iterator begin, const_iterator end)
{
auto new_memory = alloc.allocate(end - begin);
return { new_memory,std::uninitialized_copy(begin,end,new_memory) };
}
void free(){
for (iterator ptr = memory_free; ptr != _elements; )
alloc.destroy(--ptr);//free dynamically allocated memory
alloc.deallocate(_elements,memory_free-_elements);//free object allocted memeory
_elements = memory_free = _capacity = nullptr;
}
void reallocator()
{
std::size_t newCapacity = size() ? 2 * size() : 1;
iterator newmemory = alloc.allocate(newCapacity);
iterator dst = newmemory;
iterator elem = _elements;
for (std::size_t i = 0; i != size(); ++i)
alloc.construct(dst++, std::move(*elem++));
free();
_elements = newmemory;
memory_free = dst;
_capacity = _elements + newCapacity;
}
void check_n_alloc()
{
if (size() == capacity())
reallocator();
}
public:
myVector<T>() : _elements(nullptr), memory_free(nullptr), _capacity(nullptr) {}
myVector<T>(const std::initializer_list<value_type>& ls)
{
std::pair<iterator, iterator> newmemory = alloc_n_copy(ls.begin(),ls.end());
_elements = newmemory.first;
memory_free = newmemory.second;
_capacity = newmemory.second;
}
myVector<T>(const myVector<T>& rhs)
{
std::pair<iterator, iterator>newmemory = alloc_n_copy(rhs.begin(), rhs.end());
_elements = newmemory.first;
memory_free = newmemory.second;
_capacity = newmemory.second;
}
myVector<T>(myVector<T>&& rhs) : _elements(rhs._elements),
memory_free(rhs.memory_free), _capacity(rhs._capacity)
{
rhs._elements = nullptr;
rhs.memory_free = nullptr;
rhs._capacity = nullptr;
}
myVector<T>& operator=(const myVector<T>&rhs)
{
if (*this != rhs)
{
std::pair<iterator, iterator>newmemory = alloc_n_copy(rhs.begin(), rhs.end());
free();
_elements = newmemory.first;
memory_free = newmemory.second;
_capacity = newmemory.second;
}
return *this;
}
reference operator[](std::size_t index) const {
if (index > size())
throw "out of range";
return _elements[index];
}
reference operator[](std::size_t index) {
if (index > size())
throw "out of range";
return _elements[index];
}
bool operator<(const myVector<T>& rhs)
{
if (this->size() < rhs.size())
return true;
else
if (this->size() > rhs.size())
return false;
iterator rhs_element = rhs._elements;
for (iterator ptr = _elements; ptr != memory_free;)
{
if (*ptr++ > *rhs_element++)
return false;
else
return true;
}
return false;
}
bool operator==(const myVector<T>& rhs)
{
if (this->size() != rhs.size())
return false;
iterator rhs_element = rhs._elements;
for (iterator ptr = _elements; ptr != memory_free;)
{
if (*ptr++ != *rhs_element++)
return false;
}
return true;
}
bool operator!= (const myVector<T>& rhs)
{
return !(*this == rhs);
}
bool operator>(const myVector<T>& rhs)
{
return !(*this < rhs) && (*this != rhs);
}
void push_back(const T& value)
{
check_n_alloc();
alloc.construct(memory_free++,value);
}
value_type pop_back()
{
if (_elements == memory_free)
throw ("This is no element");
else
{
value_type result=_elements[size()-1];
alloc.destroy(--memory_free);
return result;
}
}
template<typename ...T>
void emplace_back(T &&... package)
{
check_n_alloc();
alloc.construct(memory_free++,std::forward<T>(package)...);
}
std::size_t size()const
{
return memory_free - _elements;
}
std::size_t capacity()const
{
return _capacity - _elements;
}
iterator begin()const
{
return _elements;
}
iterator end() const
{
return memory_free;
}
void resize(const std::size_t &length)
{
if (length == 0)
free();
else
{
iterator newmemory = alloc.allocate(length);
iterator dst = newmemory;
iterator elem = _elements;
for (std::size_t i = 0; i != size(); ++i)
alloc.construct(dst++, std::move(*elem++));
free();
T value = T();
for (std::size_t i = size(); i != length; ++i)
alloc.construct(dst++, value);
_elements = newmemory;
memory_free = dst;
_capacity = _elements + length;
}
}
void reserve(const std::size_t& length)
{
if (length > capacity())
{
iterator newmemory = alloc.allocate(length);
iterator dst = newmemory;
iterator elem = _elements;
for (std::size_t i = 0; i != size(); ++i)
alloc.construct(dst++, std::move(*elem++));
free();
_elements = newmemory;
memory_free = dst;
_capacity = _elements + length;
}
}
};
template <typename U>
std::ostream &operator<<(std::ostream& out, const myVector<U>& nums)
{
for (auto iter = nums.begin(); iter != nums.end(); ++iter)
out << *iter << " ";
out << std::endl;
return out;
}
#endif // !_MYVECTOR_H
对以上代码中涉及到的一些代码块进行解析
关于allocate和construct的分析
std::size_t newCapacity = size() ? 2 * size() : 1;
///< allocate的作用是分配大小为“nweCapacity”的空间
iterator newmemory = alloc.allocate(newCapacity);
iterator dst = newmemory;
iterator elem = _elements;
///< construct在这里的作用是通过对已分配的内存空间填充指定元素
for (std::size_t i = 0; i != size(); ++i)
alloc.construct(dst++, std::move(*elem++));
关于destroy和deallocate的分析
///< destroy 的作用就是将已分配的动态内存析构掉
for (iterator ptr = memory_free; ptr != _elements; )
alloc.destroy(--ptr);//free dynamically allocated memory
///< deallocate的作用是将该对象析构掉
alloc.deallocate(_elements,memory_free-_elements);//free object allocted memeory
destory负责调用类型的析构函数,销毁相应内存上的内容(但销毁后内存地址仍保留)
deallocate负责释放内存(此时相应内存中的值在此之前应调用destory销毁,将内存地址返回给系统,代表这部分地址使用引用-1)
本文特别重要的一个地方(emplace_back)
///<通过不断地回调该函数,将类型中的每个元素一一进行创建,切记,调用emplace_back需要给
///该类型写一个右值引用的构造函数
template<typename ...T>
void emplace_back(T &&... package)
{
check_n_alloc();
alloc.construct(memory_free++,std::forward<T>(package)...);
}
///<该构造函数不可缺少
myVector<T>(myVector<T>&& rhs) : _elements(rhs._elements),
memory_free(rhs.memory_free), _capacity(rhs._capacity)
{
rhs._elements = nullptr;
rhs.memory_free = nullptr;
rhs._capacity = nullptr;
}
对该类模板进行功能性测试
#include<iostream>
#include<cstdlib>
#include<string>
#include<memory>
#include<vector>
#include"TestQuery.h"
#include<map>
#include"MyVector.h"
#include<algorithm>
#include<iterator>
int main(int argc,char* argv[])
{
myVector<int> myString={0,1,1,2,3,3,4,5};
myVector<string> myString1;
std::cout<<myString1.size();
myString1.push_back("Hello");
myString1.push_back("world");
myString1.emplace_back("My");
std::copy(myString1.begin(), myString1.end(), std::ostream_iterator<string>(std::cout, " "));
myString1.resize(0);
myString1.reserve(5);
std::cout << myString1.size();
std::copy(myString1.begin(),myString1.end(),std::ostream_iterator<string>(std::cout," "));
std::cout << "Hello World!" << std::endl;
system("pause");
}
最终的输出结果
0
My Vector Here
0
Hello World!
请按任意键继续. . .
该类模板基本上可以实现以下几个功能
push_back、pop_back、 emplace_back、 pop_back、resize(n)、以及reserve(n),还有最终的是可以和STL本身已经写好的一些算法结合起来,例如std::copy.