【C++】vector扩容缩容

vector扩容缩容

1 扩容

一般来说,主要是重新分配内存

2 缩容

resize 缩小后,vector 的容量(capacity())可能保持不变,需要显式调用 shrink_to_fit() 来释放内存。

验证代码:

#include <vector>
#include <iostream>

template <typename T>
class TrackingAllocator {
public:
    using value_type = T;

    TrackingAllocator() = default;

    // 允许从其他类型的 TrackingAllocator 构造
    template <typename U>
    TrackingAllocator(const TrackingAllocator<U>&) {}

    // 分配内存
    T* allocate(size_t n) {
        std::cout << "分配 " << n * sizeof(T) << " 字节" << std::endl;
        return static_cast<T*>(::operator new(n * sizeof(T)));
    }

    // 释放内存
    void deallocate(T* p, size_t n) {
        std::cout << "释放 " << n * sizeof(T) << " 字节" << std::endl;
        ::operator delete(p);
    }

    // 定义相等比较运算符
    bool operator==(const TrackingAllocator&) const noexcept {
        return true; // 无状态分配器,所有实例等价
    }

    // 定义不等比较运算符(可选,C++20 前需要)
    bool operator!=(const TrackingAllocator& other) const noexcept {
        return !(*this == other);
    }
};

int main() {
    // 使用自定义分配器的 vector
    std::vector<int, TrackingAllocator<int>> vec;

    // 测试 resize 缩小是否释放内存
    vec.resize(1000);  // 触发分配
    std::cout << "Size: " << vec.size() 
              << ", Capacity: " << vec.capacity() << std::endl;

    vec.resize(10);    // 缩小 size,但 capacity 不变
    std::cout << "Size: " << vec.size() 
              << ", Capacity: " << vec.capacity() << std::endl;

    vec.shrink_to_fit(); // 显式释放多余内存
    std::cout << "Size: " << vec.size() 
              << ", Capacity: " << vec.capacity() << std::endl;

    return 0;
}

测试不同标准库实现的行为:

编译器/库resize 缩小是否自动释放内存
GCC (libstdc++)否,需 shrink_to_fit
Clang (libc++)否,需 shrink_to_fit
MSVC (MSVC STL)否,需 shrink_to_fit

注意:gcc使用shrink_to_fit时,会重新分配空间

检测是否有内存泄漏:

valgrind --tool=memcheck --leak-check=full ./your_program
<think>好的,我需要回答用户关于C++vector的存储机制和特点的问题。首先,我要回忆一下vector的基本概念。根据引用[3],vector使用连续存储空间,类似数组,支持高效的下标访问,同时能动态改变大小。这点很重要,是vector的核心特性。 接下来,我需要详细解释存储机制。连续存储意味着元素在内存中是相邻的,这样可以利用缓存 locality,提升访问速度。同时,动态扩容的机制需要说明。当元素数量超过当前量时,vector会重新分配更大的内存块,通常是当前大小的两倍,然后将旧元素拷贝过去。这个过程会导致迭代器失效,这也是用户需要注意的地方。 然后,要提到自动管理内存的特点。用户不需要手动处理内存,vector内部会自动处理扩容。但频繁的扩容可能影响性能,因此如果预先知道元素数量,可以使用reserve()预留空间,减少重新分配次数。 另外,迭代器的有效性也是关键点。在插入或删除元素时,尤其是导致扩容的情况下,迭代器、指针和引用可能会失效。比如引用[2]中的测试用例展示了迭代器的使用,但在修改vector后,迭代器可能不再有效,需要重新获取。 还要比较vector与其他器,比如list或deque的区别。vector的随机访问效率高,但中间插入删除效率较低,因为需要移动元素。这帮助用户理解适用场景。 最后,总结vector的优缺点,以及使用时的一些最佳实践,比如合理使用reserve(),避免不必要的扩容,注意迭代器失效的情况等。确保回答结构清晰,覆盖存储机制、动态扩容、内存管理、迭代器有效性等方面,同时引用提供的资料来支持观点。</think>### C++ vector 存储机制及特点 #### 1. **连续存储空间** - **物理地址连续性**:$std::vector$ 的元素在内存中以连续块的形式存储,类似传统数组。这种特性支持高效的随机访问(时间复杂度为 $O(1)$),例如通过下标运算符 `v[i]` 直接定位元素[^3]。 - **缓存友好性**:连续存储使得 CPU 缓存预取机制能高效工作,提升遍历性能。 #### 2. **动态扩容机制** - **自动量调整**:当元素数量(`size()`)超过当前量(`capacity()`)时,$std::vector$ 会自动申请一块更大的内存(通常是原量的 2 倍),并将原有元素拷贝到新内存中,释放旧内存。例如: ```cpp std::vector<int> v; v.push_back(1); // 初始量可能为 1 v.push_back(2); // 触发扩容量变为 2 v.push_back(3); // 再次触发扩容量变为 4 ``` - **性能优化**:频繁扩容会导致性能损耗,可通过 `reserve(n)` 预先分配足够量避免多次扩容。 #### 3. **内存管理特点** - **自动释放内存**:$std::vector$ 的生命周期结束后会自动释放其占用的内存,无需手动管理。 - **限制**:标准未强制要求操作,即使调用 `shrink_to_fit()`,具体行为取决于编译器实现。 #### 4. **迭代器失效场景** - **插入/删除操作**: - 尾部插入(`push_back`):若未触发扩容,仅尾后迭代器失效;若扩容,则所有迭代器失效。 - 中间插入/删除:所有迭代器、指针和引用从修改点开始失效[^2]。 - **扩容操作**:重新分配内存后,所有迭代器、指针和引用均失效。 #### 5. **与其他器的对比** | 特性 | vector | list | deque | |---------------------|--------------|--------------|--------------| | **存储连续性** | ✔️ | ❌ | 分段连续 | | **随机访问效率** | $O(1)$ | $O(n)$ | $O(1)$ | | **中间插入/删除效率**| $O(n)$ | $O(1)$ | $O(n)$ | #### 6. **应用场景建议** - **适用场景**:需要频繁随机访问、遍历操作,且尾部插入/删除为主的情况(如动态数组、矩阵运算)。 - **不适用场景**:需要频繁在中间位置插入/删除元素时,应优先选择 `std::list` 或 `std::deque`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值