向量

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

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

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

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

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

与其他动态序列容器(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};
};

C++简单实现vector的更多相关文章

  1. 转载 从最简单的vector中sort用法到自定义比较函数comp后对结构体排序的sort算法

    转载自:http://www.cnblogs.com/cj695/p/3863142.html sort函数在使用中非常好用,也非常简单,而且效率与冒泡或者选择排序不是一个数量级.本文就sort函数在 ...

  2. 【转】 从最简单的vector中sort用法到自定义比较函数comp后对结构体排序的sort算法

    sort函数在使用中非常好用,也非常简单,而且效率与冒泡或者选择排序不是一个数量级.本文就sort函数在vector中的用法分为sort函数入门用法与自定义comp比较函数比较结构体这两个最基本的功能 ...

  3. 从最简单的vector中sort用法到自定义比较函数comp后对结构体排序的sort算法

    sort函数在使用中非常好用,也非常简单,而且效率与冒泡或者选择排序不是一个数量级.本文就sort函数在vector中的用法分为sort函数入门用法与自定义comp比较函数比较结构体这两个最基本的功能 ...

  4. 【C++】从最简单的vector中sort用法到自定义比较函数comp后对结构体排序的sort算法

    sort函数在使用中非常好用,也非常简单,而且效率与冒泡或者选择排序不是一个数量级.本文就sort函数在vector中的用法分为sort函数入门用法与自定义comp比较函数比较结构体这两个最基本的功能 ...

  5. C++ STL的简单应用(vector容器专题)

    #include <iostream> #include <string> #include <stdlib.h> #include <vector> ...

  6. 自己动手实现简单的Vector

    看到今天,终于自己动手写了一个自己的vector,我这个版本的vector只有vector主要的一些操作,包括原版vector的所有构造函数,begin(),end(),size(),capacity ...

  7. C++中STL中简单的Vector的实现

    该vector只能容纳标准库中string类, 直接上代码了,StrVec.h文件内容为: #ifndef STRVEC_H #define STRVEC_H #include<iostream ...

  8. vc++简单的vector动态数组实现

    #ifndef __MYVECTOR__ #define __MYVECTOR__ #include <Windows.h> #define SUCCESS 1 // 成功 #define ...

  9. 简单的 vector

    #pragma once #include <memory.h> #include <stdlib.h> #include <iostream> using std ...

  10. C++线性序列容器<vector>简单总结

    C++线性序列容器<vector>简单总结 vector是一个长度可变的数组,使用的时候无须声明上限,随着元素的增加,Vector的长度会自动增加:Vector类提供额外的方法来增加.删除 ...

随机推荐

  1. 【Map】【List】【数组】获得两个数组的交集

    给定两个数组,编写一个函数来计算它们的交集. 示例 1: 输入: nums1 = [1,2,2,1], nums2 = [2,2] 输出: [2,2] 示例 2: 输入: nums1 = [1,2,2 ...

  2. python web连接mysql数据库

    一定要commit,否则数据库不会发生改变!!! 1.使用python写入内容到数据库 import pymysql # 记得下载并引入pymysql # 1.连接mysql,db:声明数据库 con ...

  3. win32 - 使用LookupAccountName查找SID

    可以使用LookupAccountNameA获取sid. LookupAccountName函数接受系统名称和帐户作为输入.它检索该帐户的安全标识符(SID)以及在其上找到该帐户的域的名称. 使用此a ...

  4. maven引入本地jar不能打入部署包的问题解决

    引入的三方依赖 jar 包, scope 为 system 的包 maven 默认是不打包进去的,需要加这个配置 在pom.xml文件中找到spring-boot-maven-plugin插件,添加如 ...

  5. 鸿蒙开发学习(二)之ArkUI

    目录 UI开发 布局 布局选择 布局位置 组件 容器组件 row.column RelativeContainer 列表 Tabs 子组件 页面路由 GitHub地址,欢迎star HmDemo: 鸿 ...

  6. ASP.NET Core 微信支付(三)【查询订单 APIV3】

    官方参考资料 查询订单 理论实战 官方提供两种查询订单的方式,一种是根据商户自己生成的订单号查询,一种方式是根据微信生成的订单号查询.而我使用的就是第一种方式. 调用微信支付的查询订单,需要生成签名, ...

  7. 【Azure 微服务】Service Fabric 部署时遇见了VMExtensionProvisioningError错误: Multiple VM extensions failed to be provisioned on the VM

    问题描述 Deployment  Azure Service Fabric 时,遇见了VMExtensionProvisioningError, 全文如下: Deployment Name: 385A ...

  8. TCP和UDP可以使用同一个端口号吗?

    TCP和UDP可以使用同一个端口号吗? 首先说答案:可以.怎么理解呢? 我想这个问题要从计算机网络通信谈起,学过计算机网络的同学,可能都还记得7层或者4层网络模型,TCP/UDP属于其中的传输层协议, ...

  9. C++ Qt开发:运用QThread多线程组件

    Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QTh ...

  10. BIM+物联网,打开数字孪生世界之门

    建筑行业一直在寻求创新和提高效率的方法,以满足日益复杂和迫切的建筑需求.近年来,数字孪生和物联网等新兴技术的崛起为建筑信息模型(BIM)应用带来了全新的可能性.数字孪生技术通过将实体建筑与其虚拟模型连 ...