模板实现vector\List;适配器适配栈和队列

这篇博客讨论了在实现模板类vector时遇到的深浅拷贝问题,特别是在处理如string这样的数据类型时可能出现的二次深浅拷贝错误。文章通过分析vector的内存管理和memcpy函数的使用,揭示了错误的原因。同时,博客还介绍了List、Queue和Stack的模板实现及其适配器的应用。
摘要由CSDN通过智能技术生成

1、vector.h

#pragma once
template <class T>
#include<string>//这里使用不带有.h的头文件
class vector{
public:
    void PushBack(const T& x){
        size_t size = Size();
        check_capacity();
        *_finish = x;
        _finish++;
    }

    void PopBack(){
        if (_start != _finish){
            --_finish;
        }
    }

    void Insert(size_t pos, const T& x){
        size_t size = Size();
        assert(pos <= size&&pos >= 0);
        check_capacity();
        for (size_t i = size; i > pos; i--){
            _start[i] = _start[i - 1];
        }
        _start[pos] = x;
        ++_finish;
    }

    void Erase(size_t pos){
        size_t size = Size();
        assert(pos <= size&&pos >= 0);
        for (size_t i = pos + 1; i < size; i++){
            _start[i - 1] = _start[i];
        }
        --_finish;
    }

    vector()//构造函数
        :_start(NULL)
        , _finish(NULL)
        , _endofstorage(NULL)
    {}

    vector(const vector<T>& v){
        //拷贝的时候会涉及到开空间,
        //如果拷贝的数据类型依然存在浅拷贝的问题则使用循环拷贝,切记不要使用memcpy
        size_t size = v.Size();
        T* tmp = new T[size];
        for (size_t i = 0; i < size; i++){
            tmp[i] = v[i];
        }
        delete[] _start;
        _start = tmp;
        _finish = _start + size;
        _endofstorage = _finish;
        //此处注意v的size一定要提前保存,不能使用_finish=_start+Size()
        //因为原空间已经释放Size()=finish-start就会出错
    }

    ~vector(){
        if (_start){
            delete[]_start;
            _start = _finish = _endofstorage = NULL;
        }
    }

    void Print(){
        size_t size = Size();
        for (size_t i = 0; i < size; i++){
            cout << _start[i] << " ";
        }
        cout << endl;
    }

    size_t Size(){
        return _finish - _start;
    }
    size_t Capacity(){
        return _endofstorage - _start;
    }
    void check_capacity(){
        //有错误
        /*size_t size = Size();
        size_t capacity = Capacity();
        if (size >= capacity){
            size_t n = 2 * capacity + 3;
            T* tmp = new T[n];
            delete[]_start;
            memcpy(_start, tmp, sizeof(T)*size);
            _start = tmp;
            _finish = _start + size;
            _endofstorage = _start + n;
        }*/
        if (size >= capacity){
            size_t n = 2 * capacity + 3;
            T* tmp = new T[n];
            for (size_t i = 0; i < size; i++){
                tmp[i] = _start[i];
            }
            delete[] _start;
            _start = tmp;
            _finish = _start + size;
            _endofstorage = _start + n;
        }
    }

    bool Empty(){
        return _start == _finish;
    }
    T& Front(){
        return _start[0];
    }
    const T& Front()const{
        return _start[0];
    }
    const T& Top()const{
        return *(_finish - 1);
    }
protected:
    T* _start;
    T* _finish;
    T* _endofstorage;
};

说一下vector在检查空间不够用是开空间的情况下,会涉及深浅拷贝问题,使用memcpy函数来拷贝原来的空间和数据会出错
因为这个出错不是说所有的数据类型都会出错,而是想string这样的类型本来就涉及深浅拷贝,开空间还要在涉及一次深浅拷贝,所以就有二次深浅拷贝这里写图片描述
为什么会出现这样的错误呢?
这里写图片描述
当字符长度不超过buf时,字符串存放在buf中,(buf是对象的成员)所以memcpy可以实现拷贝;但是当字符串超过那个长度就会用一个指针_start
来存放指向字符串的指针,拷贝空间时会析构原空间,所以析构掉_start
就会找不到对应的字符串了。

2、List.h

#pragma once
#include<assert.h>

template<class T>
class ListNode{
public:
    ListNode<T>* _prev;
    ListNode<T>* _next;
    T  _data;
    ListNode(const T& x)
        :_data(x)
        , _next(NULL)
        , _prev(NULL)
    {}
};


template<class T>
class List{
    typedef ListNode<T> Node;//ListNode是类名;ListNode<T>是类型
public:
    List(){
        _head = new Node(T());//利用缺省参数类型可以解决char、string等类型的参数传参
        _head->_prev = _head;
        _head->_next = _head;
    }
    ~List(){
        delete _head;
        _head = NULL;
    }
    void Insert(Node* pos, const T& x){
        assert(pos);
        //不论什么位置、有无节点都可以涵盖
        Node* pre = pos->_prev;
        Node* new_node = new Node(x);
        pre->_next = new_node;
        new_node->_prev = pre;
        new_node->_next = pos;
        pos->_prev = new_node;
    }
    void Erase(Node* pos){
        assert(pos || _head->_next != _head);
        Node* pre = pos->_prev;
        Node* next = pos->_next;
        delete pos;
        pre->_next = next;
        next->_prev = pre;
    }
    Node* Find(const T& x){
        /*if (head->_next == head){
            return NULL;
        }*/
        Node* cur = _head->_next;
        while (cur != _head){
            if (cur->_data == x){
                return cur;
            }
            cur = cur->_next;
        }
        return NULL;
    }
    void PushBack(const T& x){
        Insert(_head, x);
    }
    void PopBack(){
        Erase(_head->_prev);
    }
    void PushFront(const T& x){
        Insert(_head->_next, x);
    }
    void PopFront(){
        Erase(_head->_next);
    }
    //拷贝构造
    List(const List<T>& l){
        _head = new Node(T());
        _head->_prev = _head;
        _head->_next = _head;

        Node* cur = (l._head)->_next;
        while (cur != l._head){
            this->PushBack(cur->_data);
            cur = cur->_next;
        }
    }
    List<T>& operator=(const List<T>& l){
        if (this != &l){
            Node* cur = (l._head)->_next;
            while (cur != _head){
                this->PushBack(cur->_data);
                cur = cur->_next;
            }
        }
        return *this;
    }
    size_t Size(){
        Node* cur = _head->_next;
        size_t size = 0;
        while (cur != _head){
            size++;
            cur = cur->_next;
        }
        return size;
    }
    void Clear(){
        //删除头结点以外的节点
        Node* cur = _head->_next;
        while (cur != _head){
            Node* next = cur->_next;
            delete cur;
            cur = next;
        }
        _head->_prev = _head;
        _head->_next = _head;
    }
    bool Empty(){
        return _head->_next == _head;
    }
    const T& Front()const{
        return _head->_next->_data;
    }
    void Print(){
        Node* cur = _head->_next;
        while (cur != _head){
            cout << cur->_data << " ";
            cur = cur->_next;
        }
    }
protected:
    Node* _head;
};

3、Queue.h

#include"List.h"
#pragma once
template <class T, class Container>
class Queue{
public:
    void Push(const T& x){
        _con.PushBack(x);
    }
    void Pop(){
        _con.PopFront();
    }
    const T& Front()const{
        return _con.Front();
    }
    size_t Size(){
        return _con.Size();
    }
    bool Empty(){
        return _con.Empty();
    }
protected:
    Container _con;
};

4、Stack.h

#include"vector.h"
#pragma once
template <class T,class Container>
class Stack{
public:
    void Push(const T& x){
        _con.PushBack(x);
    }
    void Pop(){
        _con.PopBack();
    }
    const T& Top()const{
        return _con.Top();
    }
    size_t Size(){
        return _con.Size();
    }
    bool Empty(){
        return _con.Empty();
    }
protected:
    Container _con;
    //Container <T> _con;在容器这里将类型统一,
    //避免Stack<int,vector<char>> s;大于127时造成的缺陷
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值