文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

C++ vector的简单实现

2024-04-02 19:55

关注

向量

向量是序列容器,表示可以更改大小的数组。

就像数组一样,向量对其元素使用连续的存储位置,这意味着也可以使用指向其元素的常规指针上的偏移量来访问其元素,并且与数组一样高效。但与数组不同的是,它们的大小可以动态变化,它们的存储由容器自动处理。

在内部,向量使用动态分配的数组来存储其元素。可能需要重新分配此数组,以便在插入新元素时增加大小,这意味着分配新数组并将所有元素移动到该数组。就处理时间而言,这是一项相对昂贵的任务,因此,每次将元素添加到容器时,向量都不会重新分配。

相反,向量容器可以分配一些额外的存储以适应可能的增长,因此容器的实际容量可能大于严格需要的存储来包含其元素(即其大小)。库可以实现不同的增长策略,以平衡内存使用和重新分配,但无论如何,重新分配应仅以对数增长的大小间隔发生,以便可以在向量末尾插入单个元素,并提供摊销的恒定时间复杂性。

因此,与数组相比,向量消耗更多的内存,以换取管理存储和以有效方式动态增长的能力。

与其他动态序列容器(deques、list 和 forward_lists)相比,向量非常有效地访问其元素(就像数组一样),并且相对有效地从其末尾添加或删除元素。对于涉及在末尾以外的位置插入或删除元素的操作,它们的性能比其他元素差,并且迭代器和引用的一致性低于 lists 和 forward_lists。

成员函数

	(构造函数)	构造 vector(公开成员函数)
	(析构函数)	析构 vector(公开成员函数)
	operator=	赋值给容器(公开成员函数)
	assign	将值赋给容器(公开成员函数)
	get_allocator	返回相关的分配器(公开成员函数)
	
元素访问
	at	访问指定的元素,同时进行越界检查(公开成员函数)
	operator[]	访问指定的元素(公开成员函数)
	front	访问第一个元素(公开成员函数)
	back	访问最后一个元素(公开成员函数)
	data	直接访问底层数组(公开成员函数)
	
迭代器
	begin,cbegin(C++11)	返回指向起始的迭代器(公开成员函数)
	end,cend(C++11)	返回指向末尾的迭代器(公开成员函数)
	rbegin,crbegin(C++11)	返回指向起始的逆向迭代器(公开成员函数)
	rend,crend(C++11)	返回指向末尾的逆向迭代器(公开成员函数)
	
容量
	empty	检查容器是否为空(公开成员函数)
	size	返回容纳的元素数(公开成员函数)
	max_size	返回可容纳的最大元素数(公开成员函数)
	reserve	预留存储空间(公开成员函数)
	capacity	返回当前存储空间能够容纳的元素数(公开成员函数)
	shrink_to_fit(C++11)	通过释放未使用的内存减少内存的使用(公开成员函数)
	
修改器
	clear	清除内容(公开成员函数)
	insert	插入元素(公开成员函数)
	emplace(C++11)	原位构造元素(公开成员函数)
	erase	擦除元素(公开成员函数)
	push_back	将元素添加到容器末尾(公开成员函数)
	emplace_back(C++11)	在容器末尾就地构造元素(公开成员函数)
	pop_back	移除末元素(公开成员函数)
	resize	改变容器中可存储元素的个数(公开成员函数)
	swap	交换内容(公开成员函数)
	
非成员函数
按照字典顺序比较 vector 中的值(函数模板)
	operator==
	operator!=(C++20 中移除)
	operator<(C++20 中移除)
	operator<=(C++20 中移除)
	operator>(C++20 中移除)
	operator>=(C++20 中移除)
	operator<=>(C++20)
std::swap(std::vector)	特化 std::swap 算法(函数模板)
erase(std::vector),erase_if(std::vector)  (C++20)	擦除所有满足特定判别标准的元素(函数模板

cpp

template <typename T>
class Vector
{
public:
    Vector() noexcept = default;
    explicit Vector(size_t n) : cap_{n}, ptr_{alloc(cap_)}
    {
        for (; len_ < n; ++len_)
        {
            construct(ptr_ + len_); //调用T的默认构造
        }
    }
    Vector(size_t n, const T &x) : cap_{n}, ptr_{alloc(cap_)}
    {
        for (; len_ < n; ++len_)
        {
            construct(ptr_ + len_, x); //调用T的拷贝构造
        }
    }
    Vector(const Vector &x) : cap_{x.size()}, ptr_{alloc(cap_)} //拷贝构造
    {
        for (; len_ < x.size(); ++len_)
        {
            construct(ptr_ + len_, x[len_]);
        }
    }
    Vector(Vector &&x) noexcept //移动构造
    {
        cap_ = std::__exchange(x.cap_, 0);
        len_ = std::__exchange(x.len_, 0);
        ptr_ = std::__exchange(x.ptr_, nullptr);
    }
    Vector(std::initializer_list<T> li) : cap_{li.size()}, ptr_{alloc(cap_)} //初始化列表
    {
        for (auto &x : li)
        {
            construct(ptr_ + len_, x);
            ++len_;
        }
    }

    ~Vector() noexcept
    {
        clear();
        dealloc(ptr_);
    }

    void swap(Vector &x) noexcept
    {
        using std::swap; // ADL
        swap(cap_, x.cap_);
        swap(len_, x.len_);
        swap(ptr_, x.ptr_);
    }
    void clear() noexcept
    {
        for (; len_ > 0; --len_)
        {
            destroy(ptr_ + len_ - 1);
        }
    }

    Vector &operator=(const T &x) //拷贝赋值
    {
        if (this != &x)
        {
            Vector{x}.swap(*this);
        }
        return *this;
    }
    Vector &operator=(T &&x) noexcept //移动赋值
    {
        if (this != &x)
        {
            Vector{std::move(x)}.swap(*this);
        }
        return *this;
    }
    Vector &operator=(std::initializer_list<T> li) //初始化列表赋值
    {
        Vector{li}.swap(*this);
        return *this;
    }

    void push_back(const T &x) //拷贝
    {
        emplace_back(x);
    }
    void push_back(T &&x) //移动
    {
        emplace_back(x);
    }
    template <typename... Args>
    void emplace_back(Args &&...args) //直接传递构造函数
    {
        if (len_ == cap_)
        {
            size_t new_cap = cap_ ? cap_ * 2 : 1; //等0返回1
            T *new_ptr = alloc(new_cap);
            for (size_t new_len; new_len < len_; ++new_len)
            {
                construct(new_ptr + new_len, std::move_if_noexcept(ptr_[new_len]));
            }
            cap_ = new_cap;
            ptr_ = new_ptr;
        }
        construct(ptr_ + len_, std::forward<Args>(args)...);
        ++len_;
    }
    void pop_back() noexcept
    {
        if (len_ < cap_ / 2)
        {
            size_t new_cap = cap_ / 2;
            T *new_ptr = alloc(new_cap);
            for (size_t new_len = 0; new_len < len_; ++new_len)
            {
                construct(new_ptr + new_len, std::move_if_noexcept(ptr_[new_len]));
            }
            cap_ = new_cap;
            ptr_ = new_ptr;
        }
        destroy(ptr_ + len_ - 1);
        --len_;
    }
    size_t size() const noexcept
    {
        return len_;
    }
    size_t capacity() const noexcept
    {
        return cap_;
    }
    bool empty() const noexcept
    {
        return len_ == 0;
    }

    T &operator[](size_t i)
    {
        return ptr_[i];
    }
    const T &operator[](size_t i) const
    {
        return ptr_[i];
    }

    T *begin() noexcept
    {
        return ptr_;
    }
    T *end() noexcept
    {
        return ptr_ + len_;
    }
    const T *begin() const noexcept
    {
        return ptr_;
    }
    const T *end() const noexcept
    {
        return ptr_ + len_;
    }

private:
    T *alloc(size_t n) //分配n个大小内存
    {
        return static_cast<T *>(::operator new(sizeof(T) * n));
    }
    void dealloc(T *p) noexcept //释放内存
    {
        ::operator delete(p);
    }
    template <typename... Args>
    void construct(T *p, Args &&...args) //在这块内存上构造T类型对象
    {
        ::new (p) T(std::forward<Args>(args)...);
    }
    void destroy(T *p) noexcept
    {
        p->~T();
    }

private:
    size_t cap_{0}; //容量
    size_t len_{0}; //元素个数
    T *ptr_{nullptr};
};

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!   

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯