Skip to content

Performance: avoid unnecessary container copies in non-mutating returns and insert_back #30

@jkalias

Description

@jkalias

Summary

Several hot paths copy an entire std::vector / std::set where a move would do. None are correctness bugs, but they defeat the library's "make it fast" goal and are easy wins. The codebase is also internally inconsistent — some sites already move correctly.


1. Copy-instead-of-move when returning wrapper objects

Many non-mutating methods build a local std::vector / std::set and then pass it as an lvalue into a wrapper constructor that has both a copy (const T&) and a move (T&&) overload. Passing the lvalue selects the copy constructor, so the whole container is copied even though the local is about to be destroyed.

include/vector.h

  • filteredreturn vector(filtered_vector); (725)
  • sortedreturn vector(sorted_vector); (1020)
  • removing_atreturn vector(copy); (1213)
  • removing_rangereturn vector(shorter_vector); (1311)
  • inserting_back(T)return vector(augmented_vector); (1468)
  • replacing_range_at_impreturn vector(replaced_vector); (2045)
  • (and the other inserting_* / removing_* copies)

include/set.h

  • difference_withreturn set(diff); (533)
  • union_withreturn set(combined); (560)
  • intersect_withreturn set(intersection); (587)
  • filteredreturn set(copy); (841)
  • removing / insertingreturn set(copy); (969 / 999)
  • zip_implreturn set<...>(combined_set); (1199)

Fix: std::move the local into the constructor, e.g. return vector(std::move(filtered_vector));.

Note — the code already does this correctly in places, e.g. inserting_at_impl (vector.h:2008: return vector(std::move(augmented_vector));) and lazy_vector::get (vector.h:2067). So this is just a matter of consistency.


2. keys() uses a pessimizing move

Location: include/set.h:939

return std::move(vec);   // defeats NRVO, triggers -Wpessimizing-move

The map equivalents (include/map.h:498, 517) correctly return vec;. Drop the std::move so NRVO applies.


3. insert_back(T value) double-copies the element

Location: include/vector.h:1437-1441 (and inserting_back(T value), 1464-1469)

vector& insert_back(T value)
{
    m_vector.push_back(value);   // value is an lvalue here -> copies again
    return *this;
}

The parameter is taken by value (one copy/move) and then push_backed as an lvalue (a second copy). Use m_vector.push_back(std::move(value));.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions