将多个元素高效地插入 STL 容器,提升C++代码性能

一、将多个元素插入 STL 容器

在 STL 中,可以大量使用了输出迭代器,例如 std::back_inserter。虽然这样的迭代器非常方便,但在某些情况下并不想使用它们。例如,将多个连续元素插入 STL 容器。

使用 std::back_inserter 插入多个元素的次优方法是将其与 std::copy 结合使用:

std::vector<int> v;
std::vector<int> newElements = {1, 3, 4, 2, -7, 8};

std::copy(begin(newElements), end(newElements), std::back_inserter(v));

在这里,std::copy 逐个将 newElements 中的每个元素传递给输出迭代器,该迭代器通过调用其 push_back 方法将它们添加到 v 中。这完成了工作:在执行 std::copy 之后,newElements 中的所有元素都已有效地复制到 v 中。

这里的问题是,即使在调用 std::copy 之前,整个元素集合已经知道(知道有多少个元素),但此信息被丢弃了。相反,反复将元素 push_back 到向量 v 中,就好像每次都在发现还有另一个元素要追加一样。这可能会导致vector多次重新分配。

提前知道要添加多少个元素可以被vector利用。这使它能够在操作期间最大限度地减少重新分配内存次数:它会在开始操作之前一次性重新分配,而不是在多次调用 push_back 时多次重新分配。
在这里插入图片描述

那么,如何在插入vector时利用此信息呢?只需使用范围插入方法。

vector初始化时,使用范围构造函数:

std::vector<int> v{begin(newElements), end(newElements)};

为了将多个新元素追加到现有vector

v.insert(end(v), begin(newElements), end(newElements));

请注意,这些方法也存在于其他 STL 容器中,特别是 std::setstd::map

最后,要将vector的整个内容替换为 newElements

v.assign(begin(newElements), end(newElements));

在执行 assign 之后,所有先前元素都被新的元素替换,无论新旧元素的数量如何。但是,assign 方法不存在于关联容器(如 std::setstd::map)中。

二、std::copy 有用吗?

当然有用。

在上述情况下,std::copy 不合适,因为它盲目地扩展了容器的大小。但有时,不会扩展容器的大小,或者无法提前知道要添加多少个元素。

例如,如果容器已经包含值,并且想要从开头覆盖它们,可以使用 std::copy

std::vector<int> v = {5, 5, 5, 5, 5, 5, 5, 5, 5, 5};
std::vector<int> newElements = {1, 2, 3};

std::copy(begin(newElements), end(newElements), begin(v));
// v 现在包含 {1, 2, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5};

当然,v 必须大于 newElements 才能正常工作。

另一个例子是写入 C 数组:

int a[10] = {};
std::vector<int> newElements = {1, 2, 3};

std::copy(begin(newElements), end(newElements), std::begin(a));
// a 现在包含 {1, 2, 3, 0, 0, 0, 0, 0, 0, 0};

三、std::back_inserter 有用吗?

再次有用!

它通常用于将执行std::copy以外的任何算法的结果添加到容器中。例如 std::copy_if

std::vector<int> v;
std::vector<int> newElements = {1, 3, 2, 4, 3, 2, 2};

std::copy_if(begin(newElements), end(newElements), std::back_inserter(v), [](int i){return i % 2 == 0;});

在这里,没有直接的范围要插入到目标容器中,因此无法使用范围插入方法。

但是,如果知道要插入多少个元素,可以在插入之前执行 reserve,这样vector在插入期间就不会多次重新分配。在这种情况下,需要事先执行 count_if。这可能是过度使用的,取决于这段代码是否被证明是性能瓶颈。

四、总结

要将多个元素插入容器,尽可能使用容器方法:

  • 范围插入方法: 适用于已知要插入元素数量的情况,能够最大限度地减少内存重新分配,提升插入效率。
  • assign 方法: 适用于替换容器中所有元素的情况,但仅适用于序列容器,例如 std::vector

当无法使用容器方法时,可以使用 std::copystd::back_inserter 结合其他算法:

  • std::copy 适用于覆盖容器中已有元素或写入 C 数组的情况。
  • std::back_inserter 适用于将算法结果添加到容器中,例如 std::copy_if

一些额外的建议:

  • 了解容器的特性,选择最适合的插入方法。
  • 提前预估要插入的元素数量,避免频繁的内存重新分配。
  • 使用 reserve 方法预留空间,进一步提高插入效率。
  • 避免过度使用 std::copystd::back_inserter,它们可能会导致性能问题。

通过掌握这些技巧,可以有效地将多个元素插入 STL 容器,并提升代码性能。
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lion 莱恩呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值