数组实现
源代码
#include<iostream>
#include<stdexcept>
template<typename T>
class vector{
public:
vector(size_t size=10);
vector(const vector& rhs);
vector<T>& operator=(vector& rhs);
~vector();
bool full() const;
bool empty() const;
size_t size() const;
size_t capacity() const;
void push_back(T& elm);
void pop_back();
T back();
private:
T* first_;
T* last_;
T* end_;
void expand();
void copy_from(const vector& rhs);
};
template<typename T>
vector<T>::vector(size_t size)
:first_(new T[size])
,last_(first_)
,end_(first_+size)
{}
template<typename T>
vector<T>::vector(const vector& rhs)
{
copy_from(rhs);
}
template<typename T>
vector<T>& vector<T>::operator=(vector& rhs)
{
if(this!=&rhs)
{
delete []first_;
copy_from(rhs);
}
return *this;
}
template<typename T>
vector<T>::~vector()
{
delete []first_;
first_=last_=end_=nullptr;
}
template<typename T>
bool vector<T>::full() const
{
return last_==end_;
}
template<typename T>
bool vector<T>::empty() const
{
return last_==first_;
}
template<typename T>
size_t vector<T>::size() const
{
return last_-first_;
}
template<typename T>
size_t vector<T>::capacity() const{
return end_-first_;
}
template<typename T>
void vector<T>::push_back(T& elm)
{
if(full())
expand();
*last_++=elm;
}
template<typename T>
void vector<T>::pop_back()
{
if(empty())
throw std::out_of_range("vector is empty!");
--last_;
}
template<typename T>
T vector<T>::back()
{
if(empty())
throw std::out_of_range("vector is empty!");
return *(last_-1);
}
template<typename T>
void vector<T>::expand()
{
size_t old_size=last_-first_;
size_t new_size=old_size*2;
T* first=new T[new_size];
for(int i=0;i<old_size;i++)
first[i]=first_[i];
delete []first_;
first_=first;
last_=first_+old_size;
end_=first+new_size;
}
template<typename T>
void vector<T>::copy_from(const vector& rhs)
{
size_t size=rhs.last_-rhs.first_;
first_=new T[size];
for(int i=0;i<size;i++)
first_[i]=rhs.first_[i];
last_=first_+size;
end_=first_+size;
}
测试代码
#include"vector.h"
void test()
{
vector<int> vec;
for(int i=0;i<20;i++)
{
vec.push_back(i);
std::cout<<">>>"<<vec.back()<<std::endl;
std::cout<<"size="<<vec.size()<<std::endl;
std::cout<<"capacity="<<vec.capacity()<<std::endl;
}
while(!vec.empty())
{
std::cout<<vec.back()<<std::endl;
vec.pop_back();
}
}
int main()
{
test();
return 0;
}
使用空间配置器
为说明问题,我们使用上述实现的简易vector写一段测试代码
#include"vector.h"
class Test{
public:
Test(){
std::cout<<"Test"<<std::endl;
}
~Test()
{
std::cout<<"~Test()"<<std::endl;
}
};
void test()
{
vector<Test> vec;
}
int main()
{
test();
return 0;
}
编译运行输出
pcl@robot:~/projects/myPro/vector$ g++ ./vector.cc -o main -g
pcl@robot:~/projects/myPro/vector$ ./main
Test
Test
Test
Test
Test
Test
Test
Test
Test
Test
~Test()
~Test()
~Test()
~Test()
~Test()
~Test()
~Test()
~Test()
~Test()
~Test()
pcl@robot:~/projects/myPro/vector$
可以看到,我只是在测试代码里单纯的定义了一个Test自定义类型的vector而已,还什么都没有做,就无缘无故的创建了10个Test对象
其原因在于,在vector的构造函数里,内存的创建与对象的构造是一块完成的
观察构造函数的实现,我们发现first数组数据成员是用new运算符完成的,而new运算符在分配内存的同时会调用对象的构造函数
template<typename T>
vector<T>::vector(size_t size)
:first_(new T[size])
,last_(first_)
,end_(first_+size)
{}
同理,我们观察vector的析构函数可以看到,vector析构函数里释放first数组时使用的是delete运算符,而delete运算符在释放内存的同时也会调用对象的析构函数
template<typename T>
vector<T>::~vector()
{
delete []first_;
}
因此,现在我们明白,我们的需求是
- 将对象内存的分配与对象的构造分开
- 将对象内存的释放与对象的析构分开
c++语言里有一个专门的空间配置器可以完成这一任务, 这也是一个类模版,其中
基本功能:
- 内存分配:分配足够的内存以存储特定数量的对象。
- 内存释放:释放之前分配的内存。
- 构造和销毁对象:在分配的内存中构造和销毁对象。
自定义配置器:
C++ 允许用户自定义配置器,以满足特殊的内存管理需求。自定义配置器需要实现以下基本方法:
allocate()
: 分配内存。deallocate()
: 释放内存。construct()
: 在分配的内存中构造对象(在 C++11 后,这通常由容器自动管理)。destroy()
: 销毁对象(同样,C++11 后容器自动管理)。
事实上,这个空间配置器的实现原理是通过malloc和free函数实现的,因为malloc函数只进行内存的分配,而不会调用对象的构造函数,同理free函数也只进行内存的释放而不调用对象的析构
接下来,我们使用c++库为我们提供的空间配置器allocator改造我们的vector代码
源代码
#include<iostream>
#include<stdexcept>
template<typename T,typename Alloc=std::allocator<T>>
class vector{
public:
vector(size_t size=10,Alloc allocator=std::allocator<T>());
vector(const vector& rhs);
vector<T,Alloc>& operator=(vector& rhs);
~vector();
bool full() const;
bool empty() const;
size_t size() const;
size_t capacity() const;
void push_back(T& elm);
void pop_back();
T back();
private:
T* first_;
T* last_;
T* end_;
Alloc allocator_;
void expand();
void copy_from(const vector& rhs);
void destroy_vector();
};
template<typename T,typename Alloc>
vector<T,Alloc>::vector(size_t size,Alloc allocator)
// :first_(new T[size])
/*只进行内存分配而不进行对象构造*/
:first_(allocator_.allocate(size))
,last_(first_)
,end_(first_+size)
,allocator_(allocator)
{}
template<typename T,typename Alloc>
vector<T,Alloc>::vector(const vector& rhs)
{
copy_from(rhs);
}
template<typename T,typename Alloc>
vector<T,Alloc>& vector<T,Alloc>::operator=(vector& rhs)
{
if(this!=&rhs)
{
// delete []first_;
destroy_vector();
copy_from(rhs);
}
return *this;
}
template<typename T,typename Alloc>
vector<T,Alloc>::~vector()
{
// delete []first_;
/*首先析构掉有效对象,再释放内存*/
destroy_vector();
}
template<typename T,typename Alloc>
bool vector<T,Alloc>::full() const
{
return last_==end_;
}
template<typename T,typename Alloc>
bool vector<T,Alloc>::empty() const
{
return last_==first_;
}
template<typename T,typename Alloc>
size_t vector<T,Alloc>::size() const
{
return last_-first_;
}
template<typename T,typename Alloc>
size_t vector<T,Alloc>::capacity() const{
return end_-first_;
}
template<typename T,typename Alloc>
void vector<T,Alloc>::push_back(T& elm)
{
if(full())
expand();
*last_++=elm;
}
template<typename T,typename Alloc>
void vector<T,Alloc>::pop_back()
{
if(empty())
throw std::out_of_range("vector is empty!");
--last_;
}
template<typename T,typename Alloc>
T vector<T,Alloc>::back()
{
if(empty())
throw std::out_of_range("vector is empty!");
return *(last_-1);
}
template<typename T,typename Alloc>
void vector<T,Alloc>::expand()
{
size_t old_size=last_-first_;
size_t new_size=old_size*2;
// T* first=new T[new_size];
T* first=allocator_.allocate(new_size);
for(int i=0;i<old_size;i++)
{
// first[i]=first_[i];
allocator_.construct(first+i,first_[i]);
}
// delete []first_;
destroy_vector();
first_=first;
last_=first_+old_size;
end_=first+new_size;
}
template<typename T,typename Alloc>
void vector<T,Alloc>::copy_from(const vector& rhs)
{
size_t size=rhs.last_-rhs.first_;
// first_=new T[size];
/*只进行内存的分配*/
first_=allocator_.allocate(size);
for(int i=0;i<size;i++)
{
// first_[i]=rhs.first_[i];
/*进行对象的构造,第一个参数的内存地址,第二个参数为内存里要构造的值*/
allocator_.construct(first_+i,rhs.first_[i]);
}
last_=first_+size;
end_=first_+size;
}
template<typename T,typename Alloc>
void vector<T,Alloc>::destroy_vector()
{
for(T* p=first_;p!=last_;p++)
{
allocator_.destroy(p);
}
allocator_.deallocate(first_,size());
first_=last_=end_=nullptr;
}
测试代码
#include"vector.h"
class Test{
public:
Test(){
std::cout<<"Test"<<std::endl;
}
~Test()
{
std::cout<<"~Test()"<<std::endl;
}
};
void test()
{
std::cout<<">>>>"<<std::endl;
vector<Test> vec;
Test test;
std::cout<<"====="<<std::endl;
vec.push_back(test);
}
int main()
{
test();
std::cout<<"-----"<<std::endl;
return 0;
}
再次编译运行查看结果
pcl@robot:~/projects/myPro/vector$ g++ ./vector.cc -o main -g
pcl@robot:~/projects/myPro/vector$ ./main
>>>>
Test
=====
~Test()
~Test()
-----
pcl@robot:~/projects/myPro/vector$
可以看到,除了测试代码中本身定义Test对象时调用了Test的构造函数以外,再没有多余的构造函数,同样也再没有多余的析构函数
自定义空间配置器
#ifndef MY_ALLOCTOR
#define MY_ALLOCTOR
#include <cstdlib>
template <typename T>
class Alloctor {
public:
T *allocate(int size) { return (T *)malloc(size * sizeof(T)); }
void deallocte(T *ptr) { free(ptr); }
void construct(T *ptr, const T &val) { new (ptr) T(val); }
void destroy(T *ptr) { ptr->~T(); }
};
#endif
MyVector使用自定义空间配置器
#ifndef MY_VECTOR
#define MY_VECTOR
#include "myallocator.h"
#include <stdexcept>
template <typename T, typename Alloc = Alloctor<T>>
class MyVector {
public:
MyVector(int size = 5)
// : first_(new T[size]), last_(first_), end_(first_ + size){}
: first_(allocator_.allocate(size)), last_(first_),
end_(first_ + size) {}
MyVector(const MyVector &rhs) {
int size = rhs.end_ - rhs.first_;
int len = rhs.last_ - rhs.first_;
// first_ = new T[size];
first_ = allocator_.allocate(size);
for (int i = 0; i < len; ++i) {
// first_[i] = rhs.first_[i];
allocator_.construct(first_ + i, rhs.first_[i]);
}
last_ = first_ + len;
end_ = first_ + size;
}
MyVector &operator=(const MyVector &rhs) {
if (this != &rhs) {
// delete[] first_;
for (int i = 0; i < (last_ - first_); ++i) {
allocator_.destroy(first_ + i);
}
allocator_.deallocte(first_);
int size = rhs.end_ - rhs.first_;
int len = rhs.last_ - rhs.first_;
for (int i = 0; i < len; ++i) {
// first_[i] = rhs.first_[i];
allocator_.construct(first_ + i, rhs.first_[i]);
}
last_ = first_ + len;
end_ = first_ + size;
}
return *this;
}
T operator[](int &index) const {
if (index < 0 || index >= (end_ - first_)) {
throw std::out_of_range("Index out of range");
}
return *(first_ + index);
}
~MyVector() {
// delete[] first_;
for (int i = 0; i < (last_ - first_); ++i) {
allocator_.destroy(first_ + i);
}
allocator_.deallocte(first_);
first_ = last_ = end_ = nullptr;
};
bool empty() const { return end_ == first_; };
bool full() const { return last_ == end_; }
int size() const { return last_ - first_; }
int capacity() const { return end_ - first_; };
T front() const { return *first_; }
T back() const { return *(last_ - 1); }
void push_back(const T &val) {
if (full())
expand();
*(last_++) = val;
};
void pop_back() {
if (empty())
throw std::out_of_range("vector is empty!");
last_--;
};
private:
T *first_;
T *last_;
T *end_;
Alloc allocator_;
void expand() {
int old_size = end_ - first_;
int size = 2 * old_size;
// T *tmp = new T[size];
T *tmp = allocator_.allocate(size);
for (int i = 0; i < old_size; ++i) {
// tmp[i] = first_[i];
allocator_.construct(tmp + i, first_[i]);
allocator_.destroy(first_ + i);
}
// delete[] first_;
allocator_.deallocte(first_);
first_ = tmp;
last_ = first_ + old_size;
end_ = first_ + size;
tmp = nullptr;
}
};
#endif
测试代码
#ifndef LIB_TEST
#define LIB_TEST
#include <iostream>
class Test {
public:
Test();
~Test();
};
#endif
#include "lib_test.h"
Test::Test() { std::cout << "Test()" << std::endl; }
Test::~Test() { std::cout << "~Test()" << std::endl; }
#include "lib_test.h"
#include "tinyvector.h"
#include <iostream>
template <typename T>
std::ostream &operator<<(std::ostream &os, MyVector<T> &vec) {
for (int i = 0; i < vec.size(); ++i) {
os << vec[i] << " ";
}
os << std::endl;
return os;
}
void test() {
const int size = 8;
MyVector<int> v;
std::cout << "size=" << v.size() << std::endl;
std::cout << "capacity=" << v.capacity() << std::endl;
for (int i = 0; i < size; i++) {
v.push_back(i + 1);
}
std::cout << "size=" << v.size() << std::endl;
std::cout << "capacity=" << v.capacity() << std::endl;
std::cout << v << std::endl;
std::cout << "-----------------" << std::endl;
MyVector<Test> vec;
vec.push_back(Test());
}
int main() {
test();
return 0;
}
size=0
capacity=5
size=8
capacity=10
1 2 3 4 5 6 7 8
-----------------
Test()
~Test()
~Test()