C++ 中 std::iota 的效率?

Ric*_*ard 6 c++

假设我有一个向量:

vector<int> v;
Run Code Online (Sandbox Code Playgroud)

我希望它填充 0 到 9 的整数。那么我这里有几个选项:

v.resize(10);
for (int i = 0; i < 10; i++) {
  v[i] = i;
}
// or
v.reserve(10);
for (int i = 0; i < 10; i++) {
  v.push_back(i);
}
// or
iota(v.begin(), v.end(), 0);
Run Code Online (Sandbox Code Playgroud)

与其他两种方法相比,使用 std::iota 是否有任何内存/时间优势?我个人认为前两者更具可读性,尽管我可能会将其与平易近人性混为一谈,因为我无论如何都不是 C++ 专家。

小智 0

该任务有很多潜在的解决方案。

但。push_back和其他方法之间存在差异。push_back需要一个空的std::vector,而其他人则处理std::vector具有给定大小的 a 。

此外。对于 10 个元素,执行时间的增量很小。调用开销可能需要比迭代std::vector和赋值更多的时间。

因此,为了获得某种可靠的比较,我们应该更长时间、更频繁地运行循环。

预期这push_back是最慢的函数,因为内部检查是否有足够的空间。

基于范围的for循环、基于 和 do 的循环iteratorsstd::generate遵循std::iota相同的基本机制。迭代和赋值。他们还需要一个额外的变量。

多线程可能会有所帮助,但这取决于您的系统

最快的应该是“正常”循环。由于它的占地面积最小,我建议使用它。

但是,您需要检查您的系统。

请看下面的示例代码:

#include <iostream>
#include <vector>
#include <numeric>
#include <chrono>
#include <algorithm>
#include <future>
#include <array>
 
struct Timer {
    std::chrono::time_point<std::chrono::high_resolution_clock> startTime{};
    long long elapsedTime{};
    void start() { startTime = std::chrono::high_resolution_clock::now(); }
    void stop() { elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - startTime).count(); }
    friend std::ostream& operator << (std::ostream& os, const Timer& t) { return os << t.elapsedTime << " ms "; }
};

constexpr std::size_t MaxSize = 50'000'000ull;
static constexpr std::size_t NumberOfThreads = 4;
static constexpr std::size_t BlockSize = 25;
static constexpr std::size_t MaxRepetition = NumberOfThreads * BlockSize;


int fillVector(std::vector<std::size_t>& v) {
    for (std::size_t k{}; k < BlockSize; ++k)
        for (std::size_t i{}; i < MaxSize; ++i)
            v[i] = i;
    return 0;
}

int main() {
    Timer t{};
    {
        std::vector<std::size_t> v{};
        v.reserve(MaxSize);

        t.start();
        for (std::size_t r{}; r < MaxRepetition; ++r) {
            for (std::size_t i{}; i < MaxSize; ++i)
                v.push_back(i);
            v.clear();
        }
        t.stop(); std::cout << "push_back:\t\t " << t << '\n';
    }
    {
        std::vector<std::size_t> v(MaxSize);


        t.start();
        for (std::size_t r{}; r < MaxRepetition; ++r)
            for (std::size_t i{}; i < MaxSize; ++i)
                v[i] = i;
        t.stop(); std::cout << "Standard loop:\t\t " << t << '\n';

        t.start();
        for (std::size_t r{}; r < MaxRepetition; ++r)
            for (std::size_t i{}; std::size_t & vi : v) vi = i++;
        t.stop(); std::cout << "range based for loop:\t " << t << '\n';

        std::size_t k{};
        t.start();
        for (std::size_t r{}; r < MaxRepetition; ++r) {
            k = 0;
            for (auto i = v.begin(); i != v.end(); ++i)
                *i = k++;
        }
        t.stop(); std::cout << "with iterators:\t\t " << t << '\n';

        t.start();
        for (std::size_t r{}; r < MaxRepetition; ++r)
            std::generate(v.begin(), v.end(), [i = 0ull]() mutable { return i++; });
        t.stop(); std::cout << "std::generate:\t\t " << t << '\n';

        t.start();
        for (std::size_t r{}; r < MaxRepetition; ++r)
            std::iota(v.begin(), v.end(), 0);
        t.stop(); std::cout << "std::iota:    \t\t " << t << '\n';

        t.start();
        std::array<std::shared_future<int>, NumberOfThreads> dummy{};
        for (std::size_t threadNumber{}; threadNumber < NumberOfThreads; ++threadNumber) {
            dummy[threadNumber] = std::async(fillVector, std::ref(v));
        }
        for (unsigned int threadNumber{}; threadNumber < NumberOfThreads; ++threadNumber) {
            dummy[threadNumber].wait();
        }
        t.stop(); std::cout << "std::async:  \t\t " << t << '\n';
    }
}
Run Code Online (Sandbox Code Playgroud)

这会在我的 2012 年 Windows 7 计算机上产生以下输出

push_back:               8805 ms
Standard loop:           1441 ms
range based for loop:    3394 ms
with iterators:          3397 ms
std::generate:           3409 ms
std::iota:               3402 ms
std::async:              1499 ms
Run Code Online (Sandbox Code Playgroud)

对于如此小的函数来说,多线程可能没有多大意义。

使用计时功能进行的时间测量也可能不如预期准确。