C++基础 - 实现一个string的vector(类标准库行为,当前仅仅实现了push_back接口)

头文件:

//
// Created by Administrator on 2020/11/20.
//

#ifndef CPPBASE_MYSTRVEC_H
#define CPPBASE_MYSTRVEC_H

#include <memory>
#include <utility>
#include <iostream>

using namespace std;

namespace MyStrVecSpace {
    class MyStrVec {
    public:
        MyStrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}

        MyStrVec(std::initializer_list<string> list) : elements(nullptr), first_free(nullptr), cap(nullptr) {
            auto p = alloc_n_copy(list.begin(), list.end());
            elements = p.first;
            first_free = cap = p.second;
        }

        MyStrVec(const MyStrVec &rhs);

        MyStrVec(MyStrVec &&rhs);

        MyStrVec &operator=(const MyStrVec &other);

        // 重载初值列的赋值运算符
        MyStrVec &operator=(std::initializer_list<string> list);

        MyStrVec &operator=(MyStrVec &&rhs);

        ~MyStrVec();

        // 下标运算符
        string &operator[](std::size_t i) {
//            return *(elements + i);
            return elements[i];
        }

        const string &operator[](std::size_t i) const {
            return *(elements + i);
        }


        void push_back(const string &str);

        void push_back(string &&str);

        std::size_t size() const { return first_free - elements; }

        std::size_t capacity() const { return cap - elements; }

        string *begin() const { return elements; }

        string *end() const { return first_free; }

        void print(const string &info) {
            cout << info << ": ";
            for (int i = 0; i < size(); ++i) {
                cout << *(elements + i) << "  ";
            }
            cout << endl;
        }

    private:
        std::allocator<std::string> strVecAlloc; // 内存分配器,无法定义为static类型?与标准库中冲突?todo
        void free(); // 释放空间

        void reallocate(); // 分配更多内存并且拷贝元素

        void chk_n_alloc(); // 检查是否还有空间能至少插入一个元素,如果没有调用reallocate分配

        pair<string *, string *> alloc_n_copy(const string *s, const string *e);  // 拷贝n个元素
        pair<string *, string *> alloc_n_move_copy(const string *s, const string *e);  // 移动拷贝n个元素

        string *elements;
        string *first_free;
        string *cap;
    };

//    std::allocator<std::string> MyStrVec::strVecAlloc; // 内存分配器,无法定义为static类型?与标准库中冲突?todo
}
#endif //CPPBASE_MYSTRVEC_H

源文件:

//
// Created by Administrator on 2020/11/20.
//

#include "MyStrVec.h"

namespace MyStrVecSpace {
    // 拷贝构造
    MyStrVec::MyStrVec(const MyStrVec &rhs) {
        auto p = alloc_n_copy(rhs.elements, rhs.first_free);
        elements = p.first;
        first_free = p.second;
        cap = p.second;
    }

    // 移动构造
    MyStrVec::MyStrVec(MyStrVec &&rhs) {
        auto p = alloc_n_move_copy(rhs.elements, rhs.first_free);
        elements = p.first;
        first_free = p.second;
        cap = p.second;
    }

    // 拷贝赋值
    MyStrVec &MyStrVec::operator=(const MyStrVec &other) {
        if (this == &other) {
            return *this;
        }

        auto p = alloc_n_copy(other.begin(), other.end());
        free();
        elements = p.first;
        first_free = cap = p.second;
        return *this;
    }

    // 重载初值列的赋值运算符
    MyStrVec &MyStrVec::operator=(std::initializer_list<string> list) {
        auto p = alloc_n_copy(list.begin(), list.end());
        free();
        elements = p.first;
        first_free = cap = p.second;
        return *this;
    }


    // 移动赋值
    MyStrVec &MyStrVec::operator=(MyStrVec &&other) {
        if (this == &other) {
            return *this;
        }

        auto p = alloc_n_move_copy(other.begin(), other.end());
        free();
        elements = p.first;
        first_free = cap = p.second;
        return *this;
    }

// 析构
    MyStrVec::~MyStrVec() {
        free();
    }


    void MyStrVec::push_back(const string &str) {
        chk_n_alloc(); // 确保有新空间容纳新元素
        strVecAlloc.construct(first_free++, str);
    }

    void MyStrVec::push_back(string &&str) {
        chk_n_alloc(); // 确保有新空间容纳新元素
        strVecAlloc.construct(first_free++, std::move(str));
    }

    // 空间满后重新分配新空间并且移动构造元素到新空间,释放旧空间
    void MyStrVec::chk_n_alloc() {
        if (size() == capacity()) {
            reallocate();
        }
    }

    // 分配更多内存并且移动拷贝元素
    void MyStrVec::reallocate() {
        size_t newCap = size() ? 2 * size() : 1;
        string *newDst = strVecAlloc.allocate(newCap);
        string *newFree = newDst;
        for (int i = 0; i < size(); ++i) {
            strVecAlloc.construct(newFree++, std::move(*(elements + i))); // todo
        }
        // 重要,不要忘记释放旧空间
        free();
        // 更新指针
        elements = newDst;
        first_free = newFree;
        cap = elements + newCap;
    }

// 释放资源
    void MyStrVec::free() {
        if (elements) {
            // 析构对象
            for (int i = 0; i < size(); ++i) {
                strVecAlloc.destroy(--first_free);  // todo
            }
            // 释放内存
            strVecAlloc.deallocate(elements, cap - elements);
        }
    }

    // 拷贝构造n个元素
    pair<string *, string *> MyStrVec::alloc_n_copy(const string *s, const string *e) {
        auto p = strVecAlloc.allocate(e - s);  // 分配新空间
        return {p, uninitialized_copy(s, e, p)};  // 将元素拷贝到新空间中构造
    }

    // 移动构造n个元素
    pair<string *, string *> MyStrVec::alloc_n_move_copy(const string *s, const string *e) {
        auto p = strVecAlloc.allocate(e - s);  // 分配新空间
        return {p, uninitialized_copy(make_move_iterator(s), make_move_iterator(e), p)};  // 将元素移动到新空间中
    }
}

测试:

   // MyStrVec测试
    void MyStrVecTest() {
        // 初值列构造
        MyStrVecSpace::MyStrVec sv({"HELLO", "WORLD"});
        sv.print("sv");

        // 初值列赋值
        MyStrVecSpace::MyStrVec strvec;
        strvec = {"hello", "world", "hello", "motherland"};
        strvec.print("strvec");
        auto &str1 = strvec[1];
        str1 = "WORLD";
        const string &str2 = strvec[1];
        strvec.print("strvec");

        MyStrVecSpace::MyStrVec strvec1;
        strvec1.print("strvec1");
        MyStrVecSpace::MyStrVec strvec2;
        strvec2.print("strvec2");
        strvec2.push_back("hello");
        strvec2.push_back("word");
        strvec2.push_back("hello");
        strvec2.push_back("motherland");
        strvec2.print("strvec2");


        // 拷贝函数测试
        MyStrVecSpace::MyStrVec strvec3(strvec2);
        strvec3.print("strvec3");

        strvec2 = strvec1;
        strvec2.print("strvec2");

        // 移动函数测试
        MyStrVecSpace::MyStrVec strvec4(std::move(MyStrVecSpace::MyStrVec()));
        strvec4.print("strvec4");

        strvec4 = std::move(strvec1);
        strvec4.print("strvec4");

        return;
    }

参考:C++ Primier 第五版中文版 第13章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值