手写STL之vector

发布于:2025-07-11 ⋅ 阅读:(27) ⋅ 点赞:(0)

定义

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;
}


网站公告

今日签到

点亮在社区的每一天
去签到