std::vector Reallocation: noexcept Move Constructor
Question 9 / 17 • Correct so far: 0 (0 answered)
Throwing Move
struct Widget {
std::string name;
std::vector<double> payload;
Widget() : name(kPayloadSize, 'x'), payload(kPayloadSize, 1.0) {}
Widget(const Widget&) = default;
Widget(Widget&& other)
: name(std::move(other.name)), payload(std::move(other.payload)) {}
};
for (std::size_t i = 0; i < kElementCount; ++i)
v.push_back(Widget{}); Noexcept Move
struct Widget {
std::string name;
std::vector<double> payload;
Widget() : name(kPayloadSize, 'x'), payload(kPayloadSize, 1.0) {}
Widget(const Widget&) = default;
Widget(Widget&& other) noexcept
: name(std::move(other.name)), payload(std::move(other.payload)) {}
};
for (std::size_t i = 0; i < kElementCount; ++i)
v.push_back(Widget{}); Shared test data (shared-setup)
constexpr std::size_t kElementCount = 512;
constexpr std::size_t kPayloadSize = 32; Which snippet is faster?
Snippet B is faster. When std::vector needs to grow, it uses
std::move_if_noexcept to decide whether to move or copy existing elements
into the new storage. If the element type's move constructor is not marked
noexcept, std::vector falls back to copying every element on each
reallocation to preserve the strong exception guarantee. In snippet A the
move constructor has no noexcept specifier, so each reallocation performs a
deep copy of every Widget already in the vector — including its std::string
and std::vector
Benchmark results
| Snippet | CPU time / iteration | Speedup |
|---|---|---|
| Noexcept Move | 40.4 us | 1.6× |
| Throwing Move | 65 us | 1.0× |
Explore the source
Open in Compiler ExplorerQuiz complete. You can return to the question list to restart and compare.