Q:c++中向量的用法?

A:

在 C++ 中,向量(Vector) 是一种动态数组,属于标准模板库(STL)的一部分,位于 <vector> 头文件中。它提供了自动内存管理、动态扩容和丰富的成员函数,是 C++ 中最常用的容器之一。以下是向量的核心用法详解:


一、基本操作

1. 创建和初始化

#include <vector>
using namespace std;

// 空向量
vector<int> vec1;

// 指定大小和初始值
vector<int> vec2(5, 0);       // 5个元素,初始化为0: [0, 0, 0, 0, 0]

// 列表初始化 (C++11)
vector<int> vec3 = {1, 2, 3}; // [1, 2, 3]

// 从数组或另一个向量初始化
int arr[] = {4, 5, 6};
vector<int> vec4(arr, arr + 3); // [4, 5, 6]
vector<int> vec5(vec3);         // 拷贝vec3

2. 元素访问

方法 说明
vec[i] 访问第i个元素(不检查越界
vec.at(i) 访问第i个元素(越界抛出异常
vec.front() 第一个元素
vec.back() 最后一个元素
vec.data() 返回指向底层数组的指针(C++11)
vector<int> vec = {10, 20, 30};
cout << vec[1];      // 20
cout << vec.at(2);   // 30
cout << vec.front(); // 10
cout << vec.back();  // 30

3. 修改元素

vec[1] = 50;       // 直接修改: [10, 50, 30]
vec.push_back(40); // 末尾添加: [10, 50, 30, 40]
vec.pop_back();    // 删除末尾: [10, 50, 30]
vec.insert(vec.begin() + 1, 15); // 在位置1插入15: [10, 15, 50, 30]
vec.erase(vec.begin() + 2);      // 删除位置2: [10, 15, 30]
vec.clear();       // 清空向量: []

二、容量管理

方法 说明
vec.size() 当前元素个数
vec.empty() 判断是否为空
vec.capacity() 当前分配的存储容量(≥ size)
vec.reserve(n) 预分配容量(避免频繁扩容)
vec.shrink_to_fit() 释放多余容量(C++11)
vector<int> vec;
vec.reserve(100);    // 预分配100个元素的空间
cout << vec.capacity(); // 100
vec.push_back(1);
vec.shrink_to_fit(); // 容量调整为1

三、迭代器遍历

vector<int> vec = {1, 2, 3};

// 1. 常规for循环
for (size_t i = 0; i < vec.size(); ++i) {
    cout << vec[i] << " ";
}

// 2. 迭代器 (推荐)
for (auto it = vec.begin(); it != vec.end(); ++it) {
    cout << *it << " ";
}

// 3. 范围for循环 (C++11)
for (int num : vec) {
    cout << num << " ";
}

四、动态扩容机制

  • 向量在插入元素时(如 push_back),若当前容量不足,会按一定策略(通常为2倍)自动扩容。
  • 扩容代价:重新分配内存 + 拷贝原有元素。
  • 优化建议:若已知元素数量,优先使用 reserve() 预分配空间。

五、常用算法(需 <algorithm>

#include <algorithm>

vector<int> vec = {3, 1, 4, 2};

// 排序
sort(vec.begin(), vec.end());      // [1, 2, 3, 4]

// 反转
reverse(vec.begin(), vec.end());  // [4, 3, 2, 1]

// 查找(返回迭代器)
auto it = find(vec.begin(), vec.end(), 3);
if (it != vec.end()) {
    cout << "Found at index: " << it - vec.begin();
}

// 累加(需 `<numeric>`)
int sum = accumulate(vec.begin(), vec.end(), 0);

六、性能与注意事项

  1. 随机访问:O(1) 时间复杂度(与数组相同)。
  2. 插入/删除
    • 末尾操作(push_back/pop_back):O(1)。
    • 中间或头部操作:O(n)(需移动元素)。
  3. 内存连续性:向量元素在内存中连续存储,适合需要快速遍历的场景。
  4. 线程安全:非线程安全容器,多线程环境需加锁。

七、与数组的对比

特性 向量 (vector) 原生数组 (int[])
动态大小 支持自动扩容/缩容 固定大小
内存管理 自动释放内存 需手动管理
功能接口 丰富(如 push_backsort 无内置方法
性能 略慢(因封装) 更快(直接内存访问)

八、典型应用场景

  1. 替代原生数组(尤其大小不确定时)。
  2. 需要频繁在末尾增删元素(如栈或队列模拟)。
  3. 作为函数返回值或参数(避免手动内存管理)。

Q:C++怎么用vector作为函数返回值

A:

在 C++ 中,使用 vector 作为函数返回值非常方便,因为 vector 支持移动语义(C++11 引入),可以高效地返回局部变量而无需担心性能问题。以下是详细用法和注意事项:


一、直接返回局部 vector

基本语法

#include <vector>
using namespace std;

// 返回一个vector的函数
vector<int> createVector() {
    vector<int> vec = {1, 2, 3};
    return vec; // 触发移动语义(非拷贝)
}

int main() {
    vector<int> result = createVector();
    for (int num : result) {
        cout << num << " "; // 输出: 1 2 3
    }
    return 0;
}

关键点

  1. 移动语义优化
    C++11 后,返回局部 vector 会优先触发移动构造(而非拷贝),效率与返回指针/引用相当。
  2. 编译器优化(NRVO)
    多数编译器会进一步优化(Named Return Value Optimization),直接避免构造临时对象。

二、返回动态生成的 vector

动态填充后返回

vector<int> generateSquares(int n) {
    vector<int> squares;
    for (int i = 1; i <= n; ++i) {
        squares.push_back(i * i);
    }
    return squares; // 依然高效
}

通过参数返回(不推荐)

void generateSquares(int n, vector<int>& out) {
    out.clear();
    for (int i = 1; i <= n; ++i) {
        out.push_back(i * i);
    }
}
// 调用时需先构造空vector
vector<int> squares;
generateSquares(5, squares);

缺点:代码冗余,不如直接返回值清晰。


三、返回大 vector 的性能验证

对比拷贝与移动

#include <vector>
#include <iostream>
using namespace std;

vector<int> createLargeVector() {
    vector<int> vec(1000000, 42); // 100万个元素
    return vec;
}

int main() {
    vector<int> v;
    cout << "Before assignment, v.capacity(): " << v.capacity() << endl;
    v = createLargeVector(); // 移动赋值(非拷贝)
    cout << "After assignment, v.capacity(): " << v.capacity() << endl;
    return 0;
}

输出

Before assignment, v.capacity(): 0  
After assignment, v.capacity(): 1000000  

结论:实际发生了移动操作,而非深拷贝。


四、返回多维 vector

返回二维 vector

vector<vector<int>> generateMatrix(int rows, int cols) {
    vector<vector<int>> matrix(rows, vector<int>(cols, 0));
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            matrix[i][j] = i + j;
        }
    }
    return matrix;
}

调用示例

auto mat = generateMatrix(3, 3);
for (auto& row : mat) {
    for (int val : row) {
        cout << val << " ";
    }
    cout << endl;
}

输出

0 1 2  
1 2 3  
2 3 4  

五、注意事项

  1. 避免返回局部静态 vector

    vector<int>& badExample() {
        static vector<int> vec = {1, 2, 3}; // 静态变量
        return vec; // 可能引发线程安全问题
    }
    

    问题:多线程环境下不安全,且所有调用共享同一数据。

  2. 不要返回指向局部 vector 的指针/引用

    vector<int>* dangerousExample() {
        vector<int> vec = {1, 2, 3};
        return &vec; // 错误!vec将被销毁
    }
    

    问题:局部变量离开作用域后指针悬空。

  3. 明确所有权语义(C++11后无需担心)

    • 优先使用返回值而非输出参数。
    • 需要修改外部变量时,使用引用参数。

六、性能最佳实践

  1. 小对象:直接返回值(编译器优化足够高效)。
  2. 大对象:依然直接返回(移动语义保证效率)。
  3. 需要复用内存:通过参数传入 vector 并复用其内存:
    void fillVector(vector<int>& out) {
        out.assign({1, 2, 3}); // 复用现有内存
    }
    

总结

场景 推荐方式 效率
返回临时结果 直接返回 vector ⭐⭐⭐
需要复用内存 通过引用参数传递 vector ⭐⭐
多线程共享数据 返回副本或使用线程安全容器

现代 C++ 中,优先使用返回值而非输出参数!