赞
踩
std::vector 是C++标准库中的一个容器类,用于存储和操作一系列相同类型的元素。它是一个动态数组,可以根据需要自动调整大小。std::vector 提供了许多成员函数,可以方便地进行元素的插入、删除、访问和遍历操作,使用时候需要#include <vector>
其定义为:
namespace std {
template <typename T, // 任意类型T
typename Allocator = allocator<T>> // 内存分配器,一般都使用c++ 标准库默认的分配器
class vector;
}
std::vector<Elem> c; // 默认构造,产生一个空的vector, 没有任何元素
std::vector<Elem> c(c2); // copy构造, 产生一个c2同类型的vector, 并且拷贝一份c2的数据。(每个元素都需要被复制)
std::vector<Elem> c = c2; // copy构造, 产生一个c2同类型的vector, 并且拷贝一份c2的数据。(每个元素都需要被复制)
std::vector<Elem> c(rv); // move 构造函数, 建立一个新的cector, 取 rv的内容。 可以理解为原始vector 的数据指针赋值给新的vector数据指针,并且将原来的值数据指针设置为空。
std::vector<Elem> c = rv; // move 构造函数, 建立一个新的cector, 取 rv的内容。
std::vector<Elem> c(n); // 调用元素的默认构造函数生成一个大小为n的vector, 如果Elem 是基础类型,那么每个元素会初始化为随机值,如果是对象,那么调用默认构造函数,(会对每个元素都调用默认函数)
std::vector<Elem> c(n, elem); // 构造一个大小为n的vector, 每个元素都是elem
std::vector<Elem> c(begin, end); // 构造一个vector, 用区间值[beg, end) 作为元素的值,注意是左闭又开区间。相当于end不算
std::vector<Elem> c(initlist); // 列表初始化,列 std::vector<int> c({1, 2, ,3})
std::vector<Elem> c = initlist; // 列表初始化, std::vector<int> c = {1, 2, ,3};
c = c2; // 将c2赋值给c, c的旧值被替换
c = rv; // 将右值移动给c,c的旧值被替换
c = initlist; // 列表初始化 {1, 2, 3}
c.assign(n, elem); // 函数赋值,赋值n个elem给c,
c.assign(beg, end); // 注意, [beg, end), 左闭又开和构造一致
c.swap(c2); // 交换两个容器的数据
std::swap(c, c2); // 交换两个容器的数据。
所有的赋值操作,都有肯恩个调用元素的默认构造函数,拷贝构造函数,或者等于操作符, 析构函数。 如果自定义对象不想被频繁的销毁和构造,建议使用智能指针。
c.empty(); // 判断容器是否为空,相当于c.size() == 0, 为空返回true
c.size(); // 返回当前容器中的元素个数
c.max_size(); // 返回当前容器元素最大可能存储的个数
c.capacity(); // 返回 【不重新进行空间分配】情况下的元素最大容量。
c.reserve(num); // 预留空间。如果容量不够,那么将会扩大
c.reserve(num, elem); // 预分配空间,如果size变大,那么多出的元素都是elem的拷贝
c.shrink_to_fit(); // 缩减容量,来符合当前实际存在元素的个数。比如预留2000个容量,但是实际只有两个,就可以调用该函数减小内存占用
c1 == c2; // 对每一个元素都调用 等于操作符,只有所有元素相等才为true
c1 != c2; // c1 是否不等于c2 相当于 !(c1==c2)
c1 > c2;
c1 < c2;
c1 <= c2;
c1 >= c2;
c[index]; // 与c风格数组类似,返回index位置的元素,【但是不检查范围,超出范围发生未定义行为,大概率是崩溃】
c.at(index); // 函数访问,对下标进行检查,如果越界,则会抛出range-error 异常,经常配合try catch 使用,否则也基本是崩溃
c.front(); // 返回第一个元素, (不检查是否存在第一个元素) 对一个空元素调用该方法,大概率也是崩溃
c.back(); // 返回最后一个元素,(不检查是否存在最后一个元素)对一个空元素调用该方法,大概率也是崩溃
除了at()函数外,访问都应该加上判空,否则基本上是崩溃的。或者是未定义行为。
c.begin(); // 返回随机访问iterator, 指向第一个元素
c.end(); // 返回随机访问iterator, 指向最后一个元素的下一个位置。
c.cbegin(); // 返回 不可变的随机迭代器,不更改使用该迭代器,或者在加了const 的函数中使用该函数 指向第一个元素
c.cend(); // 返回 不可变的随机迭代器,不更改使用该迭代器,或者在加了const 指向最后一个元素的下一个位置。
c.rbegin(); // r 单词代表 =reverse iterator 逆向迭代器,指向末尾一个元素,back
c.rend(); // 返回逆向迭代器,指向第一个元素的上一个位置。
c.crbegin(); // const 版本rbegin
c.crend(); // const 版本rend
void c.push_back(elem); // 在容器的末尾添加一个elem的拷贝。
void c.pop_back(); // 弹出末尾元素,直接弹出不返回
iterator c.insert(pos, elem); // 在pos的前方插入一个elem的拷贝。并返回新元素的位置。 注意是pos 之前
inerator c.insert(pos, n, elem); // 在pos的前方插入n个elem的拷贝,并返回第一个新元素的位置。
iterator c.insert(pos, beg, end); // 在pos的前方插入一个区间[beg, end)内的所有元素的一份拷贝,
// 并返回新元素的iterator, 如果没有新元素,返回pos 【注意区间,和拷贝,并且在pos前】
iterator c.insert(pos, initlist); // 在pos 前方插入一个初始化列表的拷贝,并返回第一个新元素的位置,没有新元素,返回pos
iterator c.emplace(pos, args...); // 在pos前方插入一个以可变参数args为初值构造的元素,并返回新元素的位置。
void c.emplace_back(pos, args...); // 用可变参数agrs 构造一个elem, 和push_back的区别就是push_back 调用拷贝构造,这里直接构造。
iterator c.erase(pos); // erase 橡皮擦,删除的意思,删除pos位置上的元素,并返回下一个元素的位置。
iterator c.erase(beg, end); // 删除[beg, end) 区间的所有元素,返会删除区间的下一个元素位置,注意区间是左闭又开。
void c.clear(); // 清空所有的元素,容器将会被清空,但不会释放所分配的内存
std::vector<char> strHello{ 'h','e','l','l','o','\0' }; int len = strlen(&strHello[0]); // 取地址求字符串 printf("str1:%s len: %d\n", &strHello[0], len); len = strlen(strHello.data()); // data返回数据 printf("str2:%s len: %d\n", strHello.data(), len); strHello.reserve(100); //copy memcpy(&strHello[0], "123456789", strlen("123456789")); // 别忘了加'\0' strHello.push_back('\0'); len = strlen(strHello.data()); // data返回数据 printf("str3:%s len: %d\n", strHello.data(), len); strHello[3] = 'A'; printf("str4:%s len: %d\n", strHello.data(), len); // 输出: str1:hello len: 5 str2:hello len: 5 str3:123456 len: 6 str4:123A56 len: 6
void printVector(const char *name, const std::vector<int> &c) { printf("%s\tsize:%d\t [", name, c.size()); for (auto &item : c) { printf("%d,", item); } printf("]\n"); } std::vector<int> c0; printVector("c0", c0); std::vector<int> c1{ 1, 2, 3 }; // 容器拥有3个元素 1, 2, 3 printVector("c1", c1); std::vector<int> c2 = c1; // 容器拥有3个元素 1, 2, 3 printVector("c2", c2); std::vector<int> c3(5, 1); // 容器拥有 5个 元素 1 1 1 1 1 printVector("c3", c3); std::vector<int> c4(c1.begin(), c1.begin() + 2); // 不包含end,所以只有1, 2 printVector("c4", c4); std::vector<int> c5 = { 1, 2, 3}; // 列表初始化为3个元素,1,2,3 printVector("c5", c5);
// 输出
c0 size:0 []
c1 size:3 [1,2,3,]
c2 size:3 [1,2,3,]
c3 size:5 [1,1,1,1,1,]
c4 size:2 [1,2,]
c5 size:3 [1,2,3,]
#include <vector> #include <algorithm> std::vector<int> c{ 1, 2, 3, 4, 5 }; // 范围for printf("for:\t["); for (auto item : c) { printf("%d, ", item); } printf("]\n"); // 下标 printf("index:\t["); for (int i = 0, size = c.size(); i < size; i++) { printf("%d, ", c[i]); // 确保不能越界 } printf("]\n"); // 迭代器 printf("iterator:\t["); for (auto it = c.begin(), end = c.end(); it != end; it++) { printf("%d, ", *it); // 确保it != end } printf("]\n"); // 逆向迭代器 printf("reverseit:\t["); for (auto it = c.rbegin(), end = c.rend(); it != end; it++) { printf("%d, ", *it); // 确保it != end 从后往前读 } printf("]\n"); // std::for_each printf("for_each:\t["); std::for_each(c.begin(), c.end(), [](int item) { printf("%d, ", item); }); printf("]\n");
// 输出
for: [1, 2, 3, 4, 5, ]
index: [1, 2, 3, 4, 5, ]
iterator: [1, 2, 3, 4, 5, ]
reverseit: [5, 4, 3, 2, 1, ]
for_each: [1, 2, 3, 4, 5, ]
void printVector(const char *desc, const std::vector<int> &c) { printf("%s\tsize:%d\t [", desc, c.size()); for (auto &item : c) { printf("%d,", item); } printf("]\n"); } std::vector<int> c{ 1, 3}; // 变为123 在第二个位置前,插入都是pos之前 // 一定注意,begin 代表第一个元素的位置。 c.insert(c.begin() + 1, 2); printVector("insert2", c); // 变为123 456 c.insert(c.end(), { 4, 5, 6 }); printVector("insert4", c); // 删除 456 从pos开始,到end前一个 删除 插入都是左闭又开 c.erase(c.begin() + 3, c.end()); printVector("erase4", c); // 在1 后面(2前面,一定是pos 前)插入3个3 c.insert(c.begin() + 1, 3, 3); printVector("insert3", c); // 删除3个三 位置在1后面,第二个位置, 删除3个 c.erase(c.begin() + 1, c.begin() + 1 + 3); printVector("erase3", c); // 清空所有元素 c.clear(); printVector("clear", c);
// 输出
insert2 size:3 [1,2,3,]
insert4 size:6 [1,2,3,4,5,6,]
erase4 size:3 [1,2,3,]
insert3 size:6 [1,3,3,3,2,3,]
erase3 size:3 [1,2,3,]
clear size:0 []
struct Human { std::string m_name; int m_age; Human(const std::string& name, int age) : m_name(name), m_age(age) { std::cout << "human structure" << std::endl; } Human(const Human &other) : m_name(other.m_name), m_age(other.m_age) { std::cout << "human copy structure" << std::endl; } Human(Human &&other) : m_name(std::move(other.m_name)), m_age(other.m_age) { other.m_age = 0; std::cout << "human move structure" << std::endl; } ~Human() { std::cout << "humna destruction" << std::endl; } };
std::vector<Human> c;
Human knox("knox", 23);
c.push_back(knox);
// 输出
knox human structure // 是调用 Human knox("knox", 23); 调用了构造函数
knox human copy structure // push_back 调用了copy 构造函数,
knox humna destruction // 对象knox 销毁,调用析构函数
knox humna destruction // c 销毁,调用每个元素的析构
std::vector<Human> c;
Human knox("knox", 23);
c.push_back(std::move(knox));
// 输出
knox human structure // 构造knox 对象调用构造函数
knox human move structure // push_back 中std::move 调用了移动构造函数
humna destruction // knox 对象析构,knox 没打印的原因是m_name 变量被移动到容器的knox对象中了
knox humna destruction // 容器销毁,调用每个元素的析构
std::vector<Human> c;
Human knox("knox", 23);
c.emplace_back(knox);
// 输出
knox human structure // 构造对象调用构造函数
knox human copy structure // 调用拷贝构造函数
knox humna destruction //knox 对象销毁调用默认析构
knox humna destruction // 容器销毁,调用每个元素的析构
std::vector<Human> c;
c.emplace_back("knox", 23);
// 输出
knox human structure // 只有一次构造 一次析构,大大提高效率
knox humna destruction // 容器销毁,调用每个元素的析构
std::vector<Human> c;
Human knox("knox", 23);
c.emplace_back(std::move(knox));
// 输出
knox human structure
knox human move structure
humna destruction
knox humna destruction
通过上面5种情况的对比,他们的区别emplace_back 是可以直接调用构造函数,push_back是不能直接调用拷贝构造函数的,其他的copy构造,移动构造都基本差不多。
动态大小:std::vector 可以根据需要动态调整大小,可以在运行时添加或删除元素。
连续存储:std::vector 内部使用连续的内存存储元素,因此可以通过索引快速访问元素,支持随机访问。
功能丰富:std::vector 提供了丰富的成员函数和操作符,可以方便地对元素进行访问、插入、删除和修改等操作。
自动扩容:当元素数量超过当前容量时,std::vector 会自动分配更大的内存空间,并将原有元素复制到新的内存中。
内存管理:std::vector 负责管理内存,当容器不再需要时,会自动释放内存。
迭代器支持:std::vector 提供了迭代器,可以使用迭代器遍历容器中的元素。
性能高效:由于 std::vector 内部使用连续的内存,因此在访问元素时具有良好的缓存局部性,提供了较高的访问性能。
插入、删除、构造使用了区间,那么一定是左闭又开区间。
插入一定是在pos位置之前,删除一定是在pos位置上。一定要做好数组 越界检查,不然删除、插入不存在的位置,那么数组越界,基本上崩溃
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。