ericniebler / range-v3

Range library for C++14/17/20, basis for C++20's std::ranges
Other
4.15k stars 438 forks source link

`vector<weak_ptr>` null after filtering: `items | transform(<lock()>) | filter(<not null>)` #1828

Open helmesjo opened 3 months ago

helmesjo commented 3 months ago

This one hit me with a bit of surprise but I guess there might be a rationale (caching related), but couldn't find the answer.

I have some list items containing weak pointers that I would like to transform (weak.lock()) then filter (!= nullptr) where it may be destructed by another thread simultaneously, but I noticed a race condition where it passed the filtering but was still null.

auto items = std::vector<std::weak_ptr<my_type>>{};
// [..] - fill with items
auto range = items |
             views::transform(
               [](auto const& w)
               {
                 return w.lock();
               }) |
             views::filter(
               [](auto const& s)
               {
                 return s != nullptr;
               });

// while filtering the owner might have released the object.
auto res = std::vector<std::shared_ptr<my_type>>{std::begin(range), std::end(range)};

I might be totally wrong here, but conceptually I imagine it as transform extracting the instance of interest, forward (as-is, lifetime intact) to the filter which again maintains the lifetime so the end result can only be a non-null shared pointer.

Is this a bug or have I just misunderstood it?