vector容器部分源码实现

来源:互联网 发布:qq飞车软件下载 编辑:程序博客网 时间:2024/06/07 22:04

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_ALLOWEDclass 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[N];            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即被销毁。
下面是两个相关的例子,感受一下其中细微的差别:
这里写图片描述

这里写图片描述

1 0
原创粉丝点击