vector push_back()方法解析

本文深入探讨了STL中vector和array的区别,重点讲解了vector作为一种动态空间的数据结构,如何通过自动扩充空间来适应新元素的加入。同时,文章详细介绍了vector的内部机制,包括迭代器的使用、内存空间的配置和重新配置过程,以及如何通过构造函数初始化vector。

STL
vector和array的区别在于,数组为静态空间,一旦配置了就不能改变;如果需要一个更大或者更小的空间,需要重新设置数组的大小,这样才能重新配置新空间,并将元素从旧地址搬到新地址,再释放新的空间给系统。而vector是动态空间,随着新元素的加入,内部机制会自动扩充空间容纳新元素。
vector维护的是一块连续的线性空间。数据结构比较简单,通过两个迭代器start和finish分别指向配置的空间中目前被使用的头和尾,迭代器end_of_storage指向整块空间的尾。

template<class T,class Alloc=alloc>
class vector{

    
    protected:
        typedef simple_alloc<value_type,Alloc> data_allocator;
        iterator start;
        iterator finish;
        iterator end_of_storge;
    ...
}

vector提供了许多构造函数,通常采用

     vector(size_type n,const T& value){fill_initialize(n,value);}

来为vector赋大小和初值。
此时通过fill_initialize函数配置了n个空间,然后填充初值。
以下结合push_back来查看vector内存空间的变化:

int main(){
    vector<string> ex(10,"34");
    vector<string>::iterator iter;
    for(iter=ex.begin();iter!=ex.end();iter++)
        cout<<*iter;    

    cout<<"size"<<ex.size()<<"\ncapacity"<<ex.capacity();
    ex.push_back("1");
    cout<<"size"<<ex.size()<<"\ncapacity"<<ex.capacity();
    ex.push_back("3");
    cout<<"size"<<ex.size()<<"\ncapacity"<<ex.capacity();
    ex.pop_back();
    cout<<"size"<<ex.size()<<"\ncapacity"<<ex.capacity();
    ex.clear();
    cout<<"size"<<ex.size()<<"\ncapacity"<<ex.capacity();       
}

在这里插入图片描述
如图可见,首先构造了大小为10的vectror,此时配置了10个空间的大小,然后为每个空间配置了初值。当使用push_back向vector尾端添加新元素时,此时原空间不够用了。则以原先两倍的大小配置一块新空间,然后将原先的内容拷贝过来,之后在原内容尾端添加新的元素,释放原始空间。当我们对这部分空间的值clear之后,发现容量的大小仍然为之前扩容后的20个。
除此之外,当从原空间将元素拷贝到新空间之后,引起空间的重新配置,此时指向原先vector的迭代器就全部失效了。

int main()
{
    vector<int> ex(10,9);
    vector<int>::iterator iter1=ex.begin();
    cout<<*iter1<<"\n";
    ex.push_back(1);
    cout<<*iter1<<"\n";
    vector<int>::iterator iter2=ex.begin();
    cout<<*iter2<<"\n";
}

在这里插入图片描述
如图可见,当构造vector之后,大小容量均为10,当push_back新的元素时,空间重新配置了,此时先前的迭代器仍然指向原来的地址空间。

<think>嗯,用户现在想详细了解C++vectorpush_back方法。之前我已经给过他们关于vector的数学和编程方面的详细介绍,现在他们进一步询问push_back的具体用法和细节。根据用户提供的引用资料,特别是引用[2]和引用[4],我需要结合这些信息来回答。 首先,用户可能已经知道push_back的基本作用是将元素添加到vector末尾,但需要更深入的信息。比如,参数类型、内存管理机制、时间复杂度,以及可能的性能优化建议。另外,用户提供的引用[4]中提到了vectorpush_back源码,涉及到内存分配和构造分离的过程,这可能涉及到扩容机制,比如容量不够时的处理方式。 用户可能还想知道push_back在不同情况下的行为,比如添加不同类型的元素(右值、左值),以及C++11之后emplace_back的对比。此外,是否需要初始化vector才能使用push_back,这也是他们之前提到的引用[1]中的初始化问题。 还需要注意用户之前的回答中提到了动态数组的vector与链表的区别,可能在性能方面需要进一步说明push_back的均摊时间复杂度。同时,引用[3]提到pushpush_back的区别,这里需要明确说明push_backvector特有的,而push属于其他容器如stack和queue。 另外,用户可能关心异常安全性,比如在push_back过程中发生异常,vector的状态如何。此外,示例代码的展示也很重要,需要结合用户提供的代码片段,说明正确用法和常见错误。 最后,确保回答结构清晰,分点详细说明,包括基本用法、内存机制、效率分析、使用技巧和相关方法比较。同时,生成的相关问题要针对用户可能进一步关心的点,比如扩容策略、emplace_back的区别、异常处理等。</think>#### C++ vector.push_back() 方法详解 --- ### 一、基本特性与语法 1. **核心功能** `push_back()` 是 `std::vector` 的成员函数,用于在**容器末尾动态追加元素**,自动管理内存扩容[^2]。 2. **语法形式** ```cpp void push_back(const T& value); // 接受常量左值引用 void push_back(T&& value); // C++11起支持移动语义(右值引用) ``` 3. **参数要求** - 必须与 `vector` 声明的元素类型严格匹配(或可隐式转换) - 示例正确用法: ```cpp std::vector<int> vec; vec.push_back(10); // 添加字面量 int x = 20; vec.push_back(x); // 添加左值变量 vec.push_back(std::move(x)); // C++11移动语义(x将失效) ``` --- ### 二、底层实现机制 1. **内存分配策略** - 初始容量为0,首次插入时分配默认容量(通常为1) - 扩容时按**指数级增长**(如2倍旧容量),保证均摊时间复杂度为$O(1)$[^4] 2. **源码关键逻辑**(简化版)[^4] ```cpp template <class T> void vector<T>::push_back(const T& val) { if (剩余空间足够) { construct(finish, val); // 在现有内存构造对象 ++finish; // 调整尾指针 } else { insert_aux(finish, val); // 触发扩容并插入 } } ``` 3. **扩容过程** 1. 分配新内存块(原容量的2倍) 2. 复制/移动旧元素到新内存(`std::uninitialized_copy`) 3. 销毁旧元素并释放原内存 4. 插入新元素 --- ### 三、效率分析与优化 1. **时间复杂度** - 最佳情况(无需扩容):$O(1)$ - 最差情况(触发扩容):$O(n)$ - **均摊时间复杂度**:$O(1)$(数学证明参考几何级数求和) 2. **性能优化技巧** - **预分配容量**:通过 `reserve(n)` 提前分配足够空间,避免多次扩容 ```cpp std::vector<int> vec; vec.reserve(1000); // 预分配1000元素空间 for(int i=0; i<1000; ++i) vec.push_back(i); ``` - **批量插入优先**:使用范围插入(`insert`或构造函数)替代循环`push_back` - **移动语义优化**:对大型对象使用 `push_back(std::move(obj))` 避免深拷贝 --- ### 四、特殊场景处理 1. **二维vector初始化**(引用[1]示例解析) ```cpp vector<vector<int>> res; for(int i=0; i<5; i++){ res.push_back({}); // 插入空vector<int> res[i].push_back(2); // 操作子vector res[i].push_back(3); } ``` - `push_back({})` 等价于 `push_back(vector<int>())` - 每层循环创建独立子容器 2. **与`emplace_back()`对比** | 方法 | 参数类型 | 构造方式 | 效率优势场景 | |----------------|-------------|-------------------|--------------------| | `push_back` | 已有对象 | 拷贝/移动构造 | 对象已存在时 | | `emplace_back` | 构造函数参数 | 原地构造(完美转发)| 直接构造大型对象时 | --- ### 五、常见错误与排查 1. **未初始化访问** ```cpp std::vector<int> vec; vec[0] = 5; // 错误!未通过push_back/resize分配空间 ``` - 正确方式:始终用`push_back`或`resize`扩展容量后再访问 2. **迭代器失效** ```cpp auto it = vec.begin(); vec.push_back(10); // 可能触发扩容,导致it失效 *it = 5; // 未定义行为! ``` ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值