如何将修改应用于本地范围并返回它?

off*_*ull 1 c++ c++20 std-ranges

下面的代码在 g++-11.3 下使用编译--std=c++20 -D_GLIBCXX_DEBUG并执行时,会产生有关迭代器的奇怪运行时错误。range我不太确定这意味着什么,但我怀疑它与返回时超出范围的向量有关test()range没有被移动或复制,而是无论管道运算符返回什么,都只保留对range.

#include <ranges>
#include <unordered_set>
#include <vector>

auto to_unordered_set(auto && range) {
    using r_type = std::ranges::range_value_t<decltype(range)>;
    auto common = range | std::views::common;
    return std::unordered_set<r_type>(std::ranges::begin(common), std::ranges::end(common));
}

auto test() {
    std::vector<int> range {1,2,3,4,5};
    return range | std::ranges::views::transform([](auto x) { return x%2; });
}

int main() {
    auto y = to_unordered_set(test());
    return 0;
}

/*
/opt/compiler-explorer/gcc-11.3.0/include/c++/11.3.0/debug/safe_iterator.h:195:
In function:
    __gnu_debug::_Safe_iterator<_Iterator, _Sequence, 
    _Category>::_Safe_iterator(__gnu_debug::_Safe_iterator<_Iterator, 
    _Sequence, _Category>&&) [with _Iterator = 
    __gnu_cxx::__normal_iterator<int*, std::__cxx1998::vector<int, 
    std::allocator<int> > >; _Sequence = std::__debug::vector<int>; 
    _Category = std::forward_iterator_tag]

Error: attempt to copy-construct an iterator from a singular iterator.

Objects involved in the operation:
    iterator "this" @ 0x0x7ffea2b7a8c0 {
      type = __gnu_cxx::__normal_iterator<int*, std::__cxx1998::vector<int, std::allocator<int> > > (mutable iterator);
      state = singular;
    }
    iterator "other" @ 0x0x7ffea2b7a820 {
      type = __gnu_cxx::__normal_iterator<int*, std::__cxx1998::vector<int, std::allocator<int> > > (mutable iterator);
      state = singular;
      references sequence with type 'std::__debug::vector<int, std::allocator<int> >' @ 0x0x7ffea2b7a8b0
    }
*/
Run Code Online (Sandbox Code Playgroud)

无论如何,有没有办法让这样的事情发挥作用?我基本上想转换/过滤/连接/等等......一个范围并返回它(返回整个事物的副本/移动,范围和任何修改都应用于它)。

康桓瑋*_*康桓瑋 5

首先,由于std::vector本身是common_rangetransform_view也将是,所以这里common_range使用是多余的。views::common

其次也是更重要的是,range它是一个局部变量,因此一旦离开它就会被销毁test(),这使得test()return atransform_view持有一个悬空指针。

无论如何,有没有办法让这样的事情发挥作用?

感谢P2415,您可以直接返回 atransform_view应用于rvalue vector,这将构造一个owning_view将原始内容的所有权转移vector给自身的 an ,这将不再导致悬空。

#include <ranges>
#include <unordered_set>
#include <vector>

auto to_unordered_set(auto && range) {
  using r_type = std::ranges::range_value_t<decltype(range)>;
  return std::unordered_set<r_type>(
           std::ranges::begin(range), std::ranges::end(range));
}

auto test() {
  std::vector<int> range {1,2,3,4,5};
  return std::move(range) | 
    std::ranges::views::transform([](auto x) { return x%2; });
}

int main() {
  auto y = to_unordered_set(test());
}
Run Code Online (Sandbox Code Playgroud)

演示