Tested on x86_64-pc-linux-gnu, does this look OK for trunk and perhaps 14? -- >8 --
Use a local reference for the (now possibly lifetime extended) result of *__first to avoid making unnecessary copies of it. PR libstdc++/112349 libstdc++-v3/ChangeLog: * include/bits/ranges_algo.h (__min_fn::operator()): Turn local object __tmp into a reference. * include/bits/ranges_util.h (__max_fn::operator()): Likewise. * testsuite/25_algorithms/max/constrained.cc (test04): New test. * testsuite/25_algorithms/min/constrained.cc (test04): New test. --- libstdc++-v3/include/bits/ranges_algo.h | 4 +-- libstdc++-v3/include/bits/ranges_util.h | 4 +-- .../25_algorithms/max/constrained.cc | 25 +++++++++++++++++++ .../25_algorithms/min/constrained.cc | 25 +++++++++++++++++++ 4 files changed, 54 insertions(+), 4 deletions(-) diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h index bae36637b3e..e1aba256241 100644 --- a/libstdc++-v3/include/bits/ranges_algo.h +++ b/libstdc++-v3/include/bits/ranges_algo.h @@ -2945,11 +2945,11 @@ namespace ranges auto __result = *__first; while (++__first != __last) { - auto __tmp = *__first; + auto&& __tmp = *__first; if (std::__invoke(__comp, std::__invoke(__proj, __result), std::__invoke(__proj, __tmp))) - __result = std::move(__tmp); + __result = std::forward<decltype(__tmp)>(__tmp); } return __result; } diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h index 3f191e6d446..4a5349ae92a 100644 --- a/libstdc++-v3/include/bits/ranges_util.h +++ b/libstdc++-v3/include/bits/ranges_util.h @@ -754,11 +754,11 @@ namespace ranges auto __result = *__first; while (++__first != __last) { - auto __tmp = *__first; + auto&& __tmp = *__first; if (std::__invoke(__comp, std::__invoke(__proj, __tmp), std::__invoke(__proj, __result))) - __result = std::move(__tmp); + __result = std::forward<decltype(__tmp)>(__tmp); } return __result; } diff --git a/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc index e7269e1b734..717900656bd 100644 --- a/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc @@ -73,10 +73,35 @@ test03() VERIFY( ranges::max({2,3,1,4}, ranges::greater{}, std::negate<>{}) == 4 ); } +void +test04() +{ + // PR libstdc++/112349 - ranges::max/min make unnecessary copies + static int copies, moves; + struct A { + A(int m) : m(m) { } + A(const A& other) : m(other.m) { ++copies; } + A(A&& other) : m(other.m) { ++moves; } + A& operator=(const A& other) { m = other.m; ++copies; return *this; } + A& operator=(A&& other) { m = other.m; ++moves; return *this; } + int m; + }; + A r[5] = {5, 4, 3, 2, 1}; + ranges::max(r, std::less{}, &A::m); + VERIFY( copies == 1 ); + VERIFY( moves == 0 ); + copies = moves = 0; + A s[5] = {1, 2, 3, 4, 5}; + ranges::max(s, std::less{}, &A::m); + VERIFY( copies == 5 ); + VERIFY( moves == 0 ); +} + int main() { test01(); test02(); test03(); + test04(); } diff --git a/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc index 7198df69adf..d338a86f186 100644 --- a/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc +++ b/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc @@ -73,10 +73,35 @@ test03() VERIFY( ranges::min({2,3,1,4}, ranges::greater{}, std::negate<>{}) == 1 ); } +void +test04() +{ + // PR libstdc++/112349 - ranges::max/min make unnecessary copies + static int copies, moves; + struct A { + A(int m) : m(m) { } + A(const A& other) : m(other.m) { ++copies; } + A(A&& other) : m(other.m) { ++moves; } + A& operator=(const A& other) { m = other.m; ++copies; return *this; } + A& operator=(A&& other) { m = other.m; ++moves; return *this; } + int m; + }; + A r[5] = {5, 4, 3, 2, 1}; + ranges::min(r, std::less{}, &A::m); + VERIFY( copies == 5 ); + VERIFY( moves == 0 ); + copies = moves = 0; + A s[5] = {1, 2, 3, 4, 5}; + ranges::min(s, std::less{}, &A::m); + VERIFY( copies == 1 ); + VERIFY( moves == 0 ); +} + int main() { test01(); test02(); test03(); + test04(); } -- 2.47.0.148.g6a11438f43