vector容器的几个要点

本文详细探讨了C++中容器的emplace操作与insert操作的区别,分析了迭代器失效的原因及解决办法,并介绍了容器容量的增长机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. insert插入和emplace的区别

emplace操作是C++11新特性,新引入的的三个成员emlace_front、empace 和 emplace_back,这些操作构造而不是拷贝元素到容器中,这些操作分别对应push_front、insert 和push_back,允许我们将元素放在容器头部、一个指定的位置和容器尾部。
两者的区别

当调用insert时,我们将元素类型的对象传递给insert,元素的对象被拷贝到容器中,而当我们使用emplace时,我们将参数传递元素类型的构造函数,emplace使用这些参数在容器管理的内存空间中直接构造元素。

insert插入的数据需要经过 栈->寄存器->内存 ,而emplace只需要 寄存器->内存。

例子

假定d是一个Date类型的容器。

//使用三个参数的Date构造函数,在容器管理的内存空间中构造新元素。 
d.emplace_back(“2016”,”05”,”26”);
//错误,push_back没有这种用法 
d.push_back(“2016”,”05”,”26”);
//push_back()创建一个临时对象,然后将临时对象拷贝到容器中 
d.push_back(Date(“2016”,”05”,”26”));

通过例子发现,使用c++11新特性emplace向容器中添加新元素,在容器管理的内存空间中构造新元素,与insert相比,省去了构造临时对象,减少了内存开销。

2.iterator迭代器失效问题

2.1 插入失效

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    vector<int> v;
    v.push_back(1);

    std::vector<int>::iterator iter1 = v.begin();
    v.push_back(1);

    int n = *iter1;
    cout << n << endl;
    return 0;

}

上面的代码运行时崩溃,就是因为迭代器iter1在vector push_back新值后失效了。切记!
但是为什么会失效?
如果我先预先resize足够大,那么会如何呢?

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    vector<int> v;
    v.resize(4);
    v.push_back(1);

    std::vector<int>::iterator iter1 = v.begin();
    v.push_back(1);
    int n = *iter1;
    cout << n << endl;
    return 0;

}

上面的代码正常运行,因为之前resize了足够的空间,即迭代器不会失效。
我们就已给vector push_back两个元素为例。resize(1), resize(2), resize(3)程序还是会崩溃。还是容量不足,导致vector重新分配内存,而导致迭代器失效。

参考博客:http://blog.youkuaiyun.com/wangshubo1989/article/details/50334297

2.2删除失效

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

typedef vector<int> Vec;
typedef vector<int>::iterator VecIt;

void print(Vec &v)
{
    VecIt it;
    for(it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }

    cout << endl;
}

void deleteValueFromVector(Vec &v, int n = 5)
{
    VecIt it;
    for(it = v.begin(); it != v.end(); it++)
    {
        if(0 == *it % n)
        {
            v.erase(it);
        }
    }
}

int main()
{
    Vec v;
    int i = 0;
    for(i = 0; i < 21; i++)
    {
        v.push_back(i); // 不能再傻傻地用下标了
    }

    print(v);

    deleteValueFromVector(v); // 程序崩溃
    print(v);

    return 0;
}
   运行程序, 结果程序也崩溃, 可见, vector删除也存在迭代器失效的问题, 怎么改呢? 如下:
#include <iostream>
#include <vector>
using namespace std;

typedef vector<int> Vec;
typedef vector<int>::iterator VecIt;

void print(Vec &v)
{
    VecIt it;
    for(it = v.begin(); it != v.end(); it++)
    {
        cout << *it << " ";
    }

    cout << endl;
}

void deleteValueFromVector(Vec &v, int n = 5)
{
    VecIt it;
    for(it = v.begin(); it != v.end(); /*不能再自增了*/)
    {
        if(0 == *it % n)
        {
            v.erase(it); // vector元素自动向前挪动了(关联的map容器元素不会自动挪动), 所以不能再把it进行++了
        }
        else
        {
            it++;
        }
    }
}

int main()
{
    Vec v;
    int i = 0;
    for(i = 0; i < 21; i++)
    {
        v.push_back(i); // 不能再傻傻地用下标了
    }

    print(v);

    deleteValueFromVector(v); // 程序ok
    print(v);

    return 0;
}
    结果为:

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
1 2 3 4 6 7 8 9 11 12 13 14 16 17 18 19

    可见, vector迭代器失效的问题也不容忽视。

3.Capacity容量的增长方式

下面我们截取了VS2017编译器中的关于容量增长的源码:

size_type _Calculate_growth(const size_type _ Newsize) const
        {   // given _Oldcapacity and _Newsize, calculate geometric growth
        const size_type _Oldcapacity = capacity();

        if (_Oldcapacity > max_size() - _Oldcapacity / 2)
            {
            return (_Newsize);  // geometric growth would overflow
            }

        const size_type _Geometric = _Oldcapacity + _Oldcapacity / 2;

        if (_Geometric < _Newsize)
            {
            return (_Newsize);  // geometric growth would be insufficient
            }

        return (_Geometric);    // geometric growth is sufficient
        }
第一种情况:_Oldcapacity > max_size() - _Oldcapacity / 2  : 当旧容量大于(最大的可能的元素个数 - 旧容量/2)  ,直接返回Newsize大小的容量
第二种情况:_Geometric = _Oldcapacity + _Oldcapacity / 2; 即1.5倍旧容量小于Newsize,返回Newsize大小的容量。
第三种情况: 排除以上2种情况,返回1.5倍旧容量

参考博客:

map和vector的迭代器失效问题:
http://www.cnblogs.com/yuanshuang/p/5777905.html

实战c++中的vector系列–可怕的迭代器失效(vector重新申请内存):
http://blog.youkuaiyun.com/wangshubo1989/article/details/50334297

C++11新特性emplace操作:
http://blog.youkuaiyun.com/penghuicheng/article/details/51505625

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值