vector容器部分源码实现

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[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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值