C++ STL容器:std::vector

std::vector 是 C++ 标准库(STL)中最常用的序列容器之一。它提供了动态大小的数组,支持随机访问,并具有良好的性能特性。在这篇教程中,我们将从基础开始,详细讲解 std::vector 的主要特性、使用方法以及背后的实现原理。

1. std::vector 简介

std::vector 是一个动态数组容器,可以自动调整其大小。它支持快速随机访问、尾部插入和删除操作,并且在内部使用连续的内存来存储数据。这使得 std::vector 的元素可以通过下标快速访问,效率很高。

2. std::vector 的主要特性

  1. 动态大小std::vector 可以在运行时动态调整其大小。
  2. 随机访问:支持常数时间复杂度的随机访问操作(operator[]at())。
  3. 自动扩容:当需要插入更多元素时,std::vector 会自动重新分配内存。
  4. 尾部操作:支持高效的尾部插入(push_back())和删除(pop_back())。

3. std::vector 的基本用法

以下是 std::vector 的一些基本用法示例:

#include <iostream>
#include <vector>

int main() {
// 创建一个空的 vector
std::vector<int> vec;

// 向 vector 中添加元素
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);

// 访问元素
std::cout << "First element: " << vec.front() << std::endl;
std::cout << "Last element: " << vec.back() << std::endl;

// 使用索引访问元素
std::cout << "Element at index 1: " << vec[1] << std::endl;

// 遍历 vector
for (size_t i = 0; i < vec.size(); ++i) {
std::cout << "Element at index " << i << ": " << vec[i] << std::endl;
}

// 删除最后一个元素
vec.pop_back();

// 清空 vector
vec.clear();

return 0;
}

4. std::vector 的实现原理

std::vector 在内部使用动态数组来存储元素。以下是一个简化的 std::vector 实现示例:

#include <stdexcept>  // 用于异常处理
#include <initializer_list> // 支持列表初始化

template <typename T>
class vector {
private:
T* _data; // 动态数组指针
size_t _size; // 当前元素个数
size_t _capacity; // 分配的内存容量

// 内部函数:用于重新分配内存
void reallocate(size_t new_capacity) {
T* new_data = new T[new_capacity];
for (size_t i = 0; i < _size; ++i) {
new_data[i] = std::move(_data[i]);
}
delete[] _data;
_data = new_data;
_capacity = new_capacity;
}

public:
// 构造函数:默认构造
vector() : _data(nullptr), _size(0), _capacity(0) {}

// 构造函数:带容量初始化
explicit vector(size_t capacity) : _data(new T[capacity]), _size(0), _capacity(capacity) {}

// 构造函数:列表初始化
vector(std::initializer_list<T> init_list) : _data(new T[init_list.size()]), _size(init_list.size()), _capacity(init_list.size()) {
size_t index = 0;
for (const T& value : init_list) {
_data[index++] = value;
}
}

// 析构函数
~vector() {
delete[] _data;
}

// 返回容器中元素个数
size_t size() const {
return _size;
}

// 返回容器的容量
size_t capacity() const {
return _capacity;
}

// 是否为空
bool empty() const {
return _size == 0;
}

// 重载 [] 操作符
T& operator[](size_t index) {
if (index >= _size) {
throw std::out_of_range("Index out of range");
}
return _data[index];
}

const T& operator[](size_t index) const {
if (index >= _size) {
throw std::out_of_range("Index out of range");
}
return _data[index];
}

// 获取首元素
T& front() {
if (empty()) {
throw std::out_of_range("Vector is empty");
}
return _data[0];
}

const T& front() const {
if (empty()) {
throw std::out_of_range("Vector is empty");
}
return _data[0];
}

// 获取尾元素
T& back() {
if (empty()) {
throw std::out_of_range("Vector is empty");
}
return _data[_size - 1];
}

const T& back() const {
if (empty()) {
throw std::out_of_range("Vector is empty");
}
return _data[_size - 1];
}

// 添加元素到末尾
void push_back(const T& value) {
if (_size == _capacity) {
reallocate(_capacity == 0 ? 1 : _capacity * 2);
}
_data[_size++] = value;
}

// 删除末尾元素
void pop_back() {
if (empty()) {
throw std::out_of_range("Vector is empty");
}
--_size;
}

// 改变容量
void reserve(size_t new_capacity) {
if (new_capacity > _capacity) {
reallocate(new_capacity);
}
}

// 迭代器定义
using iterator = T*;
using const_iterator = const T*;

// 返回指向第一个元素的迭代器
iterator begin() {
return _data;
}

const_iterator begin() const {
return _data;
}

// 返回指向末尾的迭代器
iterator end() {
return _data + _size;
}

const_iterator end() const {
return _data + _size;
}

// 清空容器
void clear() {
_size = 0;
}

// 改变容器大小
void resize(size_t new_size, const T& value = T()) {
if (new_size > _capacity) {
reserve(new_size);
}
if (new_size > _size) {
for (size_t i = _size; i < new_size; ++i) {
_data[i] = value;
}
}
_size = new_size;
}
};

5. 关键成员函数说明

  • 构造函数和析构函数:初始化和销毁 vector 对象。
  • push_back()pop_back():分别在 vector 末尾添加和删除元素。
  • reallocate():当容器需要扩容时重新分配内存。
  • reserve():调整容器的容量,确保容器可以容纳指定数量的元素。
  • resize():调整容器的大小,可以填充新的元素。

6. 迭代器和范围基于循环

std::vector 支持范围基于的 for 循环和迭代器,使得遍历容器变得简单:

#include <vector>
#include <iostream>

int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};

// 使用范围基于的 for 循环遍历 vector
for (const auto& elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;

// 使用迭代器遍历 vector
for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;

return 0;
}

7. at() 方法

at() 是一个成员函数,提供安全的元素访问。它会对访问的索引进行范围检查,以确保索引有效。如果索引超出范围,它会抛出一个 std::out_of_range 异常。

特点:

  • 范围检查at() 方法会检查索引是否在有效范围内。如果索引无效,它会抛出异常,防止访问越界。
  • 异常处理:当发生越界时,at() 会抛出 std::out_of_range 异常。这可以帮助调试和避免潜在的程序崩溃。

示例:

#include <vector>
#include <iostream>
#include <stdexcept> // std::out_of_range

int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};

try {
// 使用 at() 访问元素
std::cout << "Element at index 2: " << vec.at(2) << std::endl;

// 尝试访问越界元素
std::cout << "Element at index 10: " << vec.at(10) << std::endl; // 这将抛出异常
} catch (const std::out_of_range& e) {
std::cerr << "Out of range error: " << e.what() << std::endl;
}

return 0;
}

8. 总结

通过迭代器和范围基于循环,std::vector 的遍历变得非常方便。

std::vector 是一个动态数组容器,支持随机访问和高效的尾部操作。

它内部使用连续的内存,提供了自动扩容的能力。


已发布

分类

来自

标签:

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注