定义
vector是表示可以改变大小的数组的序列容器,底层是线性表数组。可以使用指向其元素的常规指针上的偏移量来访问它们的元素,并且与在数组中一样高效。
但是与C语言的数组不同,它们的大小可以动态变化,容器会自动处理它们的存储。
在内部,vector 使用一个动态分配的数组来存储它们的元素。这个数组可能需要重新分配,以便在插入新元素时增大大小,这意味着分配一个新数组并将所有元素移动到其中。就处理时间而言,这是一项相对昂贵的任务,因此,vector 不会在每次向容器添加元素时重新分配。
相反,vector 容器可以分配一些额外的存储空间以适应可能的增长,因此容器的实际容量可能大于严格需要的存储容量(即容器的大小)。库可以实现不同的增长策略,以平衡内存使用和重新分配,但在任何情况下,重新分配只应在大小的对数增长间隔进行,以便在向量末尾插入单个元素可以提供摊余的恒定时间复杂度
因此,与C语言的数组相比,vector 消耗更多的内存,以换取管理存储和以高效方式动态增长的能力。
与其他动态序列容器(deques、list和forward_list)相比,vectors可以非常高效地访问其元素(就像数组一样),并相对高效地从其末尾添加或删除元素。对于涉及在结尾以外的位置插入或删除元素的操作,它们的性能比其他操作差,迭代器和引用的一致性也不如列表和转发列表。
使用示例
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void main()
{
vector<string>myvt; // 定义模板类对象
myvt.reserve(4); // 设置大小
cout << "The size is 4." << endl;
// 添加内容
myvt.push_back("1. Beijing City.");
myvt.push_back("2. Tianjin City.");
myvt.push_back("3. Shanghai City.");
myvt.push_back("4. Chongqing City.");
// 打印内容
vector<string>::iterator it;
for(it=myvt.begin();it!=myvt.end();it++)
{
cout<<*it<<endl;
}
int m=myvt.size(); // 获取大小
int n=myvt.capacity(); // 获取容量
int m1=myvt.max_size(); // 获取最大大小
cout<<"vector:myvt, size is "<<m<<endl;
cout<<"vector:myvt, capacity is "<<n<<endl;
cout<<"vector:myvt, maxsize is "<<m1<<endl;
myvt.resize(10); //重设大小
cout<<"resize: 10."<<endl;
int n1=myvt.capacity();
int n2=myvt.size();
cout<<"vector:myvt, capacity is "<<n1<<endl;
cout<<"vector:myvt, size is "<<n2<<endl;
// 如果为空值则打印 * 号
for(it=myvt.begin();it!=myvt.end();it++)
{
if(*it=="")
cout<<"******"<<endl;
cout<<*it<<endl;
}
cin.get();
}
手搓实现
● std::move(str)将左值str转换为右值引用,触发push_back(T&&)移动版本,避免字符串数据复制,提升性能。
● 扩容时,用std::move移动旧元素,避免大量拷贝。
● 移动构造函数直接转移指针,置空源对象,避免资源重复释放。
● 移动后str处于有效但未定义状态,通常为空字符串。
#include <iostream>
#include <algorithm>
template <typename T>
class MyVector
{
private:
T* data;
size_t size;
size_t capacity;
public:
MyVector() : data(nullptr), size(0), capacity(0) {}
MyVector(size_t cap) : data(new T[cap]), size(0), capacity(cap) {}
// 拷贝构造
MyVector(const MyVector& other) : data(new T[other.capacity]), size(other.size), capacity(other.capacity)
{
std::copy(other.data, other.data + size, data);
std::cout << "Copy constructor called\n";
}
// 移动构造
MyVector(MyVector&& other) noexcept : data(other.data), size(other.size), capacity(other.capacity)
{
other.data = nullptr;
other.size = 0;
other.capacity = 0;
std::cout << "Move constructor called\n";
}
void push_back(const T& val) {
if (size == capacity) {
size_t newCap = capacity == 0? 1 : capacity * 2;
T* newData = new T[newCap];
std::copy(data, data + size, newData);
delete[] data;
data = newData;
capacity = newCap;
}
data[size++] = val;
}
void push_back(T&& val)
{
if (size == capacity)
{
size_t newCap = capacity == 0? 1 : capacity * 2;
T* newData = new T[newCap];
// 利用std::move移动旧元素
for (size_t i = 0; i < size; ++i)
{
newData[i] = std::move(data[i]);
}
delete[] data;
data = newData;
capacity = newCap;
}
data[size++] = std::move(val);
}
~MyVector()
{
delete[] data;
}
friend std::ostream& operator<<(std::ostream& os, const MyVector& vec) {
for (size_t i = 0; i < vec.size; ++i) {
os << "[" << vec.data[i] << "]";
}
return os;
}
};
int main()
{
MyVector<std::string> vec;
std::string str = "Hello";
vec.push_back(str); // 调用拷贝版本
vec.push_back(std::move(str)); // 调用移动版本,str被“掏空”
std::cout << "Vector content: " << vec << std::endl;
std::cout << "Original string after move: \"" << str << "\"" << std::endl;
MyVector<std::string> vec2 = std::move(vec); // 触发移动构造
std::cout << "Moved vector content: " << vec2 << std::endl;
std::cout << "Original vector after move: " << vec << std::endl;
return 0;
}