c++performanceoptimizationstandardsstd-ranges

Why is `std::views::as_rvalue` not so cheap as `std::move_iterator`?


Consider the following code snippet (full code: https://godbolt.org/z/PMM4z9KvM):

int main() {
    {
        std::cout << "begin std::views::as_rvalue\n";
        auto iss = std::istringstream("12");
        auto is  = std::views::istream<X>(iss);
        auto _   = is | std::views::as_rvalue | std::ranges::to<std::vector>();
        std::cout << "end std::views::as_rvalue\n\n" << std::flush;
    }
    {
        std::cout << "\nbegin my::as_rvalue\n";
        auto iss = std::istringstream("12");
        auto is  = std::views::istream<X>(iss);
        auto _   = is | my::as_rvalue | std::ranges::to<std::vector>();
        std::cout << "end my::as_rvalue\n\n" << std::flush;
    }
}

The output is as follows:

begin std::views::as_rvalue
X()
X(X const&)
X(X&&)
~X()
X(X&&)
X(X&&)
X(X&&)
~X()
~X()
end std::views::as_rvalue

~X()
~X()
~X()

begin my::as_rvalue
X()
X(X&&)
X(X&&)
X(X&&)
~X()
end my::as_rvalue

~X()
~X()
~X()

It seems std::views::as_rvalue has more operations than my::as_rvalue.

Why is std::views::as_rvalue not so cheap as std::move_iterator?


Solution

  • As with all standard range adaptors, std::views::as_rvalue<V> stores a copy of the adapted view V. It's constructor is effectively defined as:

    constexpr explicit as_rvalue_view(V base) : base(std::move(base_)) {}
    

    This accounts for the extra copy and move constructions, and destructions.