【C++】C++中的std::fill函数使用详解

目录

一.std::fill函数介绍

1.函数原型

2.函数使用

3.注意事项

4.函数性能

5.替代方法

二. 初始化容器的其他方法

1.使用构造函数初始化

2.使用范围构造函数

3.使用赋值操作符

4.使用 std::fill_n

5.使用循环手动初始化

6.使用 std::generate 或 std::generate_n

7.使用 std::copy 或 std::copy_n

8.使用容器的 assign 方法

三.std::fill 和 std::fill_n的差异

1.性能差异

2.示例代码


一.std::fill函数介绍

std::fill 是C++标准库中的一个函数,定义在 <algorithm> 头文件中。

std::fill作用:它用于将指定的值赋给一个给定范围内的所有元素,常用于数据结构初始化

下面是对 std::fill 的代码实例: 

#include <algorithm> // 包含 std::fill
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::fill(vec.begin(), vec.end(), 0); // 将 vec 中的所有元素设置为 0
    return 0;
}

1.函数原型

std::fill 有几种不同的重载形式,但最常用的是:


template<class ForwardIterator, class T> void fill(ForwardIterator first, ForwardIterator last, const T& value);
  • ForwardIterator: 一个前向迭代器,可以是指向容器元素的迭代器,如 std::vectorstd::list 等。
  • T: 赋值的类型,可以是任意可赋值类型。
  • first: 范围的起始迭代器。
  • last: 范围的结束迭代器(不包括在内)。
  • value: 要赋给范围内每个元素的值。

2.函数使用

#include <algorithm> // 包含 std::fill
#include <vector>

int main() {
    std::vector<int> vec = {1, 2, 3, 4, 5};
    std::fill(vec.begin(), vec.end(), 10); // 将 vec 中的所有元素设置为 10

    int arr[] = {1, 2, 3, 4, 5};
    std::fill(std::begin(arr), std::end(arr), 20); // 使用 std::begin 和 std::end 来获取数组的迭代器

    std::list<int> lst = {1, 2, 3, 4, 5};
    std::fill(lst.begin(), lst.end(), 30); // 将 list 中的所有元素设置为 30

    return 0;
}

3.注意事项

  • std::fill 会改变 first 和 last 之间的所有元素,包括 first 但不包括 last
  • 如果 first 和 last 是相同的迭代器,或者 last 在 first 之前,那么 std::fill 不会执行任何操作。
  • std::fill 可以用于任何类型的迭代器,只要它们支持解引用和赋值操作。
  • 使用 std::fill 时,需要确保 value 的类型与容器元素的类型兼容。

4.函数性能

std::fill 通常用于快速初始化或重置容器中的元素。它的性能取决于赋值操作的复杂性,但对于简单的数据类型,如整数或指针,性能通常非常高效。

5.替代方法

对于某些容器,如 std::vectorstd::array 等,它们提供了自己的 fill 方法,用于将所有元素初始化为一个特定的值。你可以使用它们的构造函数或成员函数 fill 来初始化容器。例如:

std::vector<int> vec(10, 1); // 创建一个大小为 10 的 vector,所有元素初始化为 1
std::array<int, 5> arr = {0, 1, 2, 3, 4};
arr.fill(2); // 将 arr 中的所有元素设置为 2

这些替代方法通常在初始化容器时使用,而 std::fill 更适用于在容器已经存在时修改其内容。

二. 初始化容器的其他方法

在C++中,除了使用 std::fill 来初始化容器,还可以使用以下几种方法:

1.使用构造函数初始化

对于大多数标准库容器,如 std::vectorstd::arraystd::deque 等,你可以在创建容器时使用构造函数来初始化元素。

std::vector<int> vec(10, 100); // 创建一个包含10个元素的vector,每个元素初始化为100 std::array<int, 5> arr = {1, 2, 3, 4, 5}; // 创建一个array,使用大括号初始化

2.使用范围构造函数

 如果你有一个初始化列表或者一个范围,你可以使用范围构造函数来初始化容器。

std::vector<int> vec = {1, 2, 3, 4, 5}; // 使用花括号初始化vector std::list<int> lst(std::begin(vec), std::end(vec)); // 使用另一个容器的元素范围来初始化list

3.使用赋值操作符

对于某些容器,如 std::vector,你可以使用赋值操作符来初始化或重新初始化容器。

std::vector<int> vec; vec = {1, 2, 3, 4, 5}; // 使用花括号对vector进行赋值初始化

4.使用 std::fill_n

std::fill_nstd::fill 的一个变体,它接受一个计数参数,将一个值赋给从起始迭代器开始的指定数量的元素。

int arr[5]; std::fill_n(std::begin(arr), 5, 1); // 将前5个元素设置为1

5.使用循环手动初始化

虽然这不是一个算法,但在某些情况下,你可能需要手动使用循环来初始化容器。

std::vector<int> vec(10); for (int i = 0; i < vec.size(); ++i) { vec[i] = i * 2; // 初始化每个元素为它的索引乘以2 }

6.使用 std::generatestd::generate_n

这些算法可以用来生成一个值的序列,并将它们赋给容器中的元素。

std::vector<int> vec(10); std::generate(vec.begin(), vec.end(), [&] { return rand() % 100; }); // 使用 lambda 表达式生成随机数 std::generate_n(std::back_inserter(vec), 5, [&] { return rand() % 100; }); // 向vec添加5个随机数

7.使用 std::copystd::copy_n

如果你有一个源范围,你可以使用 std::copystd::copy_n 来初始化容器。

int arr[5] = {1, 2, 3, 4, 5}; std::vector<int> vec; vec.reserve(5); std::copy(std::begin(arr), std::end(arr), std::back_inserter(vec)); // 复制arr到vec

8.使用容器的 assign 方法

某些容器提供了 assign 方法,可以用来替换容器中的所有元素。

std::vector<int> vec; vec.assign({1, 2, 3, 4, 5}); // 使用初始化列表重新初始化vec

这些方法可以根据你的具体需求和场景选择使用。

三.std::fill 和 std::fill_n的差异

std::fillstd::fill_n 都是C++标准库中的算法,用于初始化一系列元素,但它们在性能上的差异主要体现在使用场景和效率上:

  1. std::fill

    • std::fill 接受两个迭代器和一个值作为参数,将迭代器范围内的所有元素设置为给定的值。
    • 它通常用于填充一个已知范围,例如容器的开始到结束。
  2. std::fill_n

    • std::fill_n 接受一个迭代器、一个计数和一个值作为参数,将迭代器开始的指定数量的元素设置为给定的值。
    • 它适用于需要填充固定数量元素的场景。

1.性能差异

  • 效率

  std::fill_n 通常比 std::fill 更高效,因为它直接知道要填充的元素数量,不需要迭代到容器的末尾。这减少了迭代次数,特别是在处理大型容器时,可以显著提高性能。

  • 使用场景

  std::fill 更适用于填充直到容器末尾的所有元素,而 std::fill_n 更适用于已知需要填充的元素数量,但不一定知道容器的末尾迭代器。

  • 循环优化

  现代编译器可能会对 std::fill_n 进行更好的循环优化,因为它提供了明确的循环次数,这有助于编译器进行更有效的指令调度和循环展开。

  • 内存访问模式

    两者在内存访问模式上相似,都是连续写入操作,但由于 std::fill_n 的循环次数已知,可能在某些情况下获得更好的内存访问模式优化。

2.示例代码

// 假设有一个非常大的容器 int value = 42; 
// 使用 std::fill 
std::vector<int> vec(1000000); std::fill(vec.begin(), vec.end(), value); 
// 使用 std::fill_n 
std::fill_n(vec.begin(), vec.size(), value);

在实际应用中,如果你知道要填充的元素数量,使用 std::fill_n 通常是更好的选择,因为它提供了更好的性能优化机会。然而,如果你需要填充直到容器末尾的所有元素,std::fill 是更合适的选择。在某些情况下,两者的性能差异可能非常小,尤其是在容器较小或编译器优化非常有效的情况下。

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

菜鸟赵大宝

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

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

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

打赏作者

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

抵扣说明:

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

余额充值