std::list Traversal: Forward vs Two-Ended
Question 3 / 12 • Correct so far: 0 (0 answered)
List Forward
std::uint64_t sumList(const std::list<std::uint64_t>& items) {
std::uint64_t sum = 0;
for (std::uint64_t value : items)
sum += value;
return sum;
}
std::uint64_t result = sumList(values); List Two Ended
std::uint64_t sumList(const std::list<std::uint64_t>& items) {
if (items.empty())
return 0;
std::uint64_t sum = 0;
auto left = items.begin();
auto right = std::prev(items.end());
while (left != right && std::next(left) != right) {
sum += *left;
sum += *right;
++left;
--right;
}
sum += *left;
if (left != right)
sum += *right;
return sum;
}
std::uint64_t result = sumList(values); Shared test data (shared-setup)
constexpr std::size_t LIST_SIZE = 1 << 15;
static std::list<std::uint64_t> values;
struct ListInit {
ListInit() {
for (std::size_t index = 0; index < LIST_SIZE; ++index)
values.push_back((index * 1315423911u) ^ (index << 7));
}
} _list_init; Which snippet is faster?
Snippet B is faster because it exposes more independent work to the CPU on each loop iteration. While one pointer chase is waiting on memory, the processor can advance work on the other end of the list using out-of-order execution, which is similar in spirit to loop unrolling and improves overlap of memory latency.
Benchmark results
| Snippet | CPU time / iteration | Speedup |
|---|---|---|
| List Forward | 29.3 us | 1.0× |
| List Two Ended | 14.9 us | 2.0× |
Explore the source
Open in Compiler ExplorerQuiz complete. You can return to the question list to restart and compare.