深入C++04:模板编程

📕模板编程

函数模板

模板意义:对类型也进行参数化;

函数模板:是不编译的,因为类型不知道

模板的实例化:函数调用点进行实例化,生成模板函数

模板函数:这才是要被编译器所编译的

函数模板、模板的特例化、非模板函数(普通函数):函数模板只是一个模板,模板特例化是明确类型,还有普通函数;三者不是重载关系;

模板代码是不可以在一个文件中定义,在另一个文件中使用的;模板代码调用之前,一定要看到模板定义的地方,这样的化,模板才能够进行正常的实例化,产生能够被编译器编译的代码;所以,模板代码都是放在头文件中,然后源文件当中直接进行#include包含(#include会展开代码)

类模板

利用类模板实现的顺序栈

#include
#include

template
class SeqStack {
public:
    SeqStack(int size = 10) //构造函数
        : _pstack(new T[size])
        , _top(0) //top一开始就指向空的地方,所以后面也是一直要指向空的地方
        , _size(size)
    {}
    ~SeqStack() { //析构函数
        delete []_pstack;
        _pstack = nullptr;
    }
    SeqStack(const SeqStack &stack) { //拷贝构造函数
        _pstack = new T[stack._size];
        _top = stack._top;
        _size = stack._size;
        for (int i = 0; i < _size; i++) {
            _pstack[i] = stack._pstack[i];
        }
    }
    SeqStack operator=(const SeqStack &stack) { //赋值函数重载
        if (stack == *this) return *this;
        delete _pstack;
        T *_newstack = new T[stack._size];
        for (int i = 0; i < stack._size; i++) {
            _newstack[i] = stack._pstack[i];
        }
        _pstack = _newstack;
        _size = stack._size;
        _top = stack._top;
        return *this;
    }

    void push(const T &val) {
        if (full()) resize();
        _pstack[_top++] = val;
    }
    void pop() {
        if (empty()) return;
        --_top;
    }
    T top() const {
        if (empty()) throw "stack is empty!";//抛出异常也属于函数逻辑结束,不需要和返回值一致
        return _pstack[_top - 1];
    }
    bool full() const {
        return _top == _size;
    }
    bool empty() const {
        return _top == 0;
    }
private:
    T *_pstack;
    int _top;
    int _size;
    void resize() {//扩容函数
        T *newstack = new T[_size * 2];
        for (int i = 0; i < _size; i++) {
            newstack[i] = _pstack[i];
        }
        _size = _size * 2;
        delete []_pstack;
        _pstack = newstack;
    }
};

int main() {
    SeqStack test;
    for (int i = 0; i < 20; i++) {
        test.push(i);
    }
    for (int i = 0; i < 20; i++) {
        std::cout << test.top() << std::endl;
        test.pop();
    }

    return 0;
}

实现vector模板

#include

template
class vector {
public:
    vector(int size = 10)
        : _first(new T[size])
        , _last(_first)
        , _end(_first + size)
    {}
    ~vector() {
        delete []_first;
        _first = _last = _end = nullptr;
    }
    vector(const vector &other) {
        int size = other._end - other._first;
        _first = new T[size];
        int len = other._last - other._first;
        for (int i = 0; i < len; i++) {
            _first[i] = other._first[i];
        }
        _last = _first + len;
        _end = _first + size;
    }
    vector& operator=(const vector &other) {
        if (*this = other) return *this;
        delete []_first;

        int size = other._end - other._first;
        _first = new T[size];
        int len = other._last - other._first;
        for (int i = 0; i < len; i++) {
            _first[i] = other._first[i];
        }
        _last = _first + len;
        _end = _first + size;
        return *this;
    }
    void push_back(const T &val) { //向容器末尾添加元素
        if (full()) resize();
        *_last = val;
        _last++;
    }
    void pop_back() {//从容器末尾删除元素
        if (empty()) return;
        _last--;
    }
    T back() const { //返回容器末尾元素
        if (empty()) throw "no value";
        return *(_last - 1);
    }
    bool full() const { return _last == _end; }
    bool empty() const { return _first == _last; }
    int size() const {return _last - _first;}
private:
    T *_first;//数组起始位置
    T *_last;//数组中有效元素的后继位置
    T *_end;//数组中有效空间的后继位置
    void resize() {//2倍扩容操作
        int len = _end - _first;
        T *newvector = new T[len * 2];
        for (int i = 0; i < len; i++) {
            newvector[i] = _first[i];
        }
        delete []_first;
        _first = newvector;
        _last = _first + len;
        _end = _first + len * 2;
    }
};
int main() {
    vector test;
    for (int i = 0; i < 20; i++) {
        test.push_back(i);
    }
    for (int i = 0; i < 20; i++) {
        std::cout << test.back() << std::endl;
        test.pop_back();
    }
    return 0;
}

空间配置器

上述vector模板的两个问题:

①在创建类test作为vector的对象的时候,系统默认使用了十次所存对象的构造函数(默认构造十个对象), new不仅开辟了空间,同时也生成了对象!(这样很浪费,比如用户要初始化vector一万次,实际只用一个,浪费了创建的9999个对象额外的内存和时间(内存指的是对象指向的堆内存,而存对象所需要的内存在vector里面是必须一开始就要申请的))

②创建了多少个对象就会析构多少次,上述创建那么多个对象,肯定也会析构那么多次,浪费时间;而如果把内存呢开辟和对象构造分开处理,析构的时候直接采用delete的话:只析构_first,那么只析构了这个指针所指的对象;而析构[] _first,析构会死循环,后面有内存但是不是对象;

应该:

深入C++04:模板编程

③push_back的时候,里面原本就有对象了的,只是更改了指向,原存在的对象会丢弃,造成内存泄漏

④pop_back的时候只是_last–,没有析构对象,对象中可能还有堆空间,会找不到的;(应该要调用对象的析构函数);但是如果单纯的使用delete,不仅不会调用析构函数析构该位置的对象,还会删除该位置的内存

容器的空间配置器四件事情:内存开辟/内存释放,对象构造/对象析构;

代码:

#include

using namespace std;

//实现自己的空间配置器
template
class Allocator { //class
public:
    T *allocate(size_t size) {//分配内存
        return (T*)malloc(sizeof(T) * size);
    }
    void deallocate(T *p) {//释放内存
        free(p);
    }
    void construct(T *p, const T &val) {//对象构造,明确是传入指针和引用
        new (p) T(val); //定位new,指定new的区域,同时采用拷贝构造函数生成对象;
    }
    void destroy(T *p) {//对象析构
        p->~T(); //~T()代表了T类型的析构函数;
    }
};
template >
class vector {
public:
    vector(int size = 10) //构造函数
        : _first(_allocator.allocate(size) )
        , _last(_first)
        , _end(_first + size)
    {}

    ~vector() {
        for (T *p = _first; p != _last; p++) {
            _allocator.destroy(p);//析构有效对象
        }
        _allocator.deallocate(_first);//释放所有空间
        _first = _last = _end = nullptr;
    }
    vector(const vector &other) { //拷贝构造函数
        int size = other._end - other._first;
        // _first = new T[size];
        _allocator.allcoate(size);
        int len = other._last - other._first;
        for (int i = 0; i < len; i++) {
            // _first[i] = other._first[i];
            _allocator.construct(_first + i, other._first[i]); //构造对象
        }
        _last = _first + len;
        _end = _first + size;
    }
    vector& operator=(const vector &other) {
        if (*this = other) return *this;
        // delete []_first;
        //和析构的一样
        for (T *p = _first; p != _last; p++) {
            _allocator.destory(p);//析构有效对象
        }
        _allocator.deallocate(_first);//释放所有空间

        //和拷贝构造的一样
        int size = other._end - other._first;
        int len = other._last - other._first;
        _allocator.allcoate(size);
        for (int i = 0; i < len; i++) {
            _allocator.construct(_first + i, other._first[i]);
        }
        _last = _first + len;
        _end = _first + size;
        return *this;
    }
    void push_back(const T &val) { //向容器末尾添加元素
        if (full()) resize();
        _allocator.construct(_last, val);
        _last++;
    }
    void pop_back() {//从容器末尾删除元素
        if (empty()) return;
        _allocator.destroy(--_last);
    }
    T back() const { //返回容器末尾元素
        if (empty()) throw "no value";
        return *(_last - 1);
    }
    bool full() const { return _last == _end; }
    bool empty() const { return _first == _last; }
    int size() const {return _last - _first;}
private:
    T *_first;//数组起始位置
    T *_last;//数组中有效元素的后继位置
    T *_end;//数组中有效空间的后继位置
    Alloc _allocator;//定义容器空间配置器对象!!!!!
    void resize() {//2倍扩容操作
        int len = _end - _first;
        // T *newvector = new T[len * 2];
        T *newvector = _allocator.allocate(2 * len);
        for (int i = 0; i < len; i++) {
            // newvector[i] = _first[i];
            _allocator.construct(newvector + i, _first[i]);
        }
        // delete []_first;
        for (T *p = _first; p != _last; p++) {
            _allocator.destroy(p);
        }
        _allocator.deallocate(_first);
        _first = newvector;
        _last = _first + len;
        _end = _first + len * 2;
    }
};
struct Test {
  Test() {
    cout << "Test()" << endl;
  }

  ~Test() {
    cout << "~Test()" << endl;
  }

  Test(const Test &t) {
    cout << "Test(const Test&)" << endl;
  }

  Test& operator=(const Test& t) {
    cout << "operator=(const Test&)" << endl;
  }
};

int main() {
  Test t1;
  Test t2;
  vector vec;
  vec.push_back(t1);
  vec.push_back(t2);
  cout << "===========================" << endl;
  vec.pop_back();
  cout << "===========================" << endl;
  return 0;
}

深入C++04:模板编程

Original: https://www.cnblogs.com/D-booker/p/16351308.html
Author: D-booker
Title: 深入C++04:模板编程

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/715039/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球