您的位置:首页 > 其它

vector容器部分源码实现

2016-05-22 15:15 387 查看
STL中vector部分源码实现

本次作业要求自己模仿实现STL中vector部分函数

为了检测内存的管理机制是否是像源码一样,额外写了一个test类,通过输出来检测是否一样。

test代码如下:

#ifndef __TEST_H__
#define __TEST_H__

#include <memory>
#include <iostream>

class testAllocator : public std::allocator<int> {
public:
//这个函数用来申请内存,但是并不在上面创建新的变量,其中size是要申请的内存大小
typedef std::allocator<int> Base;
int * allocate(std::size_t size) {
std::cout << "Test Allocator: allocate" << std::endl;
return Base::allocate(size);        //调用了memory库中的allocate函数,下面同理
}
//这个函数用来释放内存,并不涉及调用在这片内存上面变量的析构函数,其中p是这片内存的首地址,size是这片地址的大小
void deallocate(int * p, std::size_t size) {
std::cout << "Test Allocator: deallocate" << std::endl;
Base::deallocate(p, size);
}
//在已经申请了的内存上面创建一个新的变量,其中p是一个指针,指向我们要创建新的变量的地址,val是变量的值
void construct(int * p, int val) {
std::cout << "Test Allocator: Construct, value: " << val
<< std::endl;
Base::construct(p, val);
}
//在指针p指向的内存上,销毁掉变量,但是并不释放内存
void destroy(int * p) {
std::cout << "Test Allocator: Destroy, value: " << *p << std::endl;
Base::destroy(p);
}
};

#endif


为了防止一些人投机取巧使用#define myVector std::vector

所以额外写出了一个类base来防止这种情况

#ifndef __BASE_H__
#define __BASE_H__

#define vector NOT_ALLOWED
#define define NOT_ALLOWED

class Base {};

#endif


在类myVector中要继承自定义的Base,这样就可以防止#define myVector std::vector的情况

因为STL的vector是不可能继承自自定义的Base的,在测试函数中有一句是检查是否继承自Base

接下来放上具体代码,并解释其中一些写的过程中觉得比较难懂的知识点

//
//  vector.h:
//  C++
//
//  Created by 舒俊淮 on 16/5/22.
//  Copyright © 2016年 Shujh. All rights reserved.
//
#ifndef __VECTOR_H__
#define __VECTOR_H__
#define A Alloc()
#include "base.h"
#include "memory"
#include "test.h"
using namespace std;
/*typename Alloc = std::allocator<T>这是一个模板变量,类型名叫Alloc,接受分配器,如这里的testAllocator
“= std::allocator<T>”的意思是,默认调用T类型的allocator,比如写的是myVector<int>,没有提供第二个参数,就使用默认值*/
template< typename T, typename Alloc = std::allocator<T> >
class myVector : public Base {
public:
typedef T* iterator;
typedef const T* const_iterator;
myVector() {
/*这里用A.allocate()而不是直接allocate()的原因是allocate是一个类中的公共函数,不能直接调用
A.allocate()其实就是Alloc().allocate()先用Alloc()这个默认构造函数构造一个临时对象,之后在调用它的成员函数allocate()
这种做法是可行的,而且因为创建的是临时变量,这种做法是合理的*/
_data = A.allocate(1);
_capacity = 1;
_size = 0;
}
myVector(const size_t &n, const T &ele, Alloc _A = Alloc()) {
//Alloc在这个例子被实例化成testAllocator,Alloc _A = Alloc()就是创建一个testAllocator对象
_data = _A.allocate(n);
_capacity = n;
for (int i = 0; i < n; ++i)
_A.construct(_data + i, ele);
_size = n;
}
template<typename InputIterator>
myVector(InputIterator begin, InputIterator end, Alloc _A = Alloc()) {
_size = end - begin;
_data = _A.allocate(_size);
for (int i = 0; i < _size; ++i)
_A.construct(_data + i, *(begin + i));
_capacity = _size;
}
myVector(const myVector &other) {
_size = other._size;
_capacity = other._capacity;
_data = A.allocate(_capacity);
for (int i = 0; i < _size; ++i)
A.construct(_data + i, *(other._data + i));
}
~myVector() {
if (_data) {
for (int i = 0; i < _size; ++i)
A.destroy(_data + i);
A.deallocate(_data, _capacity);
}
}
myVector & operator=(const myVector &other) {
if (other._data != _data) {
if (_data) {
for (int i = 0; i < _size; ++i)
A.destroy(_data + i);
A.deallocate(_data, _capacity);
}
_size = other._size;
_capacity = other._capacity;
_data = A.allocate(_capacity);
for (int i = 0; i < _size; ++i)
A.construct(_data + i, *(other._data + i));
}
return *this;
}
iterator begin() {return _data;}
const_iterator begin() const {return _data;}
iterator end() {return _data + _size;}
const_iterator end() const {return _data + _size;}
// Capacity
size_t size() const {return _size;}
void resize(const size_t &num) {
if (num > _size) {
if (num > _capacity) {
int new_cap = _capacity * 2;
while (new_cap < num)
new_cap *= 2;
reserve(new_cap);
}
for (int i = _size; i < num; ++i)
A.construct(_data + i, T());
_size = num;
} else {
for (int i = num; i < _size; ++i)
A.destroy(_data + i);
_size = num;
}
}
void resize(const size_t &num, const T &n) {
if (num > _size) {
if (num > _capacity) {
int new_cap = _capacity * 2;
while (new_cap < num)
new_cap *= 2;
reserve(new_cap);
}
for (int i = _size; i < num; ++i)
A.construct(_data + i, n);
_size = num;
} else {
for (int i = num; i < _size; ++i)
A.destroy(_data + i);
_size = num;
}
}
size_t capacity() const {return _capacity;}
bool empty() const {return _size == 0 ? true : false;}
void reserve(const size_t &newCap) {
if (newCap > _capacity) {
T* tmp = A.allocate(newCap);
for (int i = 0; i < _size; ++i) {
A.construct(tmp + i, _data[i]);
A.destroy(_data + i);
}
A.deallocate(_data, _capacity);
_capacity = newCap;
_data = tmp;
}
}
// Element Access
T & operator[](const size_t &index) {
if (index < _size) return *(_data + index);
}
const T & operator[](const size_t &index) const {
if (index < _size) return *(_data + index);
}
T & front() {return *(_data);}
const T & front() const {return *(_data);}
T & back() {return *(_data + _size - 1);}
const T & back() const {return *(_data + _size - 1);}
T * data() {return _data;}
const T * data() const {return _data;}
// Modifiers
template<typename InputIterator>
void assign(InputIterator begin, InputIterator end) {
clear();
_size = end - begin;
if (_size < _capacity) {
for (int i = 0; i < _size; ++i)
A.construct(_data + i, *(begin + i));
} else {
A.deallocate(_data, _capacity);
_capacity = _size;
_data = A.allocate(_capacity);
for (int i = 0; i < _size; ++i)
A.construct(_data + i, *(begin + i));
}
}
void assign(const size_t &size, const T &n) {
clear();
_size = size;
if (_size < _capacity) {
for (int i = 0; i < _size; ++i)
A.construct(_data + i, n);
} else {
A.deallocate(_data, _capacity);
_capacity = _size;
_data = A.allocate(_capacity);
for (int i = 0; i < _size; ++i)
A.construct(_data + i, n);
}
}
void push_back(const T &n) {
if (_size < _capacity) {
A.construct(_data + _size, n);
_size++;
} else {
int N = _size;
int arr
;
for (int i = 0; i < _size; ++i)
arr[i] = *(_data + i);
A.deallocate(_data, _capacity);
_capacity *= 2;
_data = A.allocate(_capacity);
for (int i = 0; i < _size; ++i)
A.construct(_data + i, arr[i]);
A.construct(_data + _size, n);
_size++;
}
}
void pop_back() {
if (_size) {
A.destroy(_data + _size - 1);
_size--;
}
}
void clear() {
if (_size) {
for (int i = 0; i < _size; ++i)
A.destroy(_data + i);
_size = 0;
}
}
private:
iterator _data;
size_t _size, _capacity;
};
#endif


下面是测试函数:

#include <iostream>
#include "test.h"
#include "base.h"
#include "vector.h"

int main() {
typedef myVector<int, testAllocator> v;
//这个函数,利用一个Base指针来检查myVector是否继承自Base,如若不是,那么便过不了编译
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;
}


最后,说明一下在写的过程中个人比较迷惑最后弄懂了的知识点:

首先,一般来说出了作用域所有变量都会被析构。

而临时对象被析构的时间比较早,是在创建它的语句执行完之后,立刻被析构!

比如上面函数中的Alloc().allocate(),Alloc()是一个类的默认构造函数,它创建一个对象并且使用了类的成员函数allocate()。

执行完这个语句之后,这个刚刚被创建的对象就会被销毁。所以上面的代码不会出现类Alloc的对象堆积如山的情况。

为什么上面的代码要这么写呢?因为我们需要用到testAllocator这个类中的函数,又不想声明太多的testAllocator对象(很浪费),所以采用了临时变量的方法。

至于如何判断临时对象,一个简单的方法是看看它被构造之后有没有引用指向它,即,构造的时候有没有左值!

比如下面两行:

temp = Alloc();这里创建的不是一个临时变量,所以temp的析构是发生在退出作用域时。

Alloc();这个创建了一个临时变量,在执行完该语句之后立刻被析构。(调用析构函数~Alloc())

还有一种情况是for语句,如:

for (int i = 0; i < 5; ++i) {}

在for语句执行完之后,临时变量i即被销毁。

下面是两个相关的例子,感受一下其中细微的差别:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  源码 管理 内存 stl