Transform iterator assignment change - #2753
danhoeflinger wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates transform_iterator’s copy assignment behavior so the stored unary functor is copied via destruction + copy-construction (rather than relying on _UnaryFunc::operator=), aiming to support functors that are copy-constructible but not copy-assignable (e.g., C++17 lambdas) and avoid ill-formed assignment operator instantiation traps.
Changes:
- Reworks
transform_iterator::operator=to copy the unary functor using explicit destruction followed by placement-new copy construction. - Adds a self-assignment guard around the functor-copy portion of the assignment operator.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (this != std::addressof(__input)) | ||
| { | ||
| __my_unary_func_ = __input.__my_unary_func_; | ||
| __my_unary_func_.~_UnaryFunc(); | ||
| ::new (std::addressof(__my_unary_func_)) _UnaryFunc(__input.__my_unary_func_); | ||
| } |
There was a problem hiding this comment.
Yes, I considered this.
The problem with std::is_assignable_v is that it only checks for the existence of the function, and does not attempt to instantiate it. For template functions where such an assignment is not well-formed this results in a compilation error (this is part of the motivation for this change).
As for the throwing copy resulting in double delete. In this case there is no easy way out. We could implement this as a std::optional or similar equivalent, changing the layout, and marking such an occasion where no constructed functor exists, but then what happens when someone wants to dereference transform_iterator without a constructed functor? I suppose we would need to throw?
Signed-off-by: Dan Hoeflinger <dan.hoeflinger@intel.com>
|
I open this PR for discussion. I'm not sure if it is the right path, but it is an option and solves a real reported issue facing a user. Similar to the current code, it has pros and cons. |
This PR switches
transform_iteratorcopy assignment to use placement new copy construction for the unary functor.(breaking change)
transform_iteratorcurrently skips assignment of the unary functor if no copy assignment exists by checking constexpris_copy_assignable_v. (explained here )However,
is_copy_assignable_vonly checks for the existence of a copy assignment operator, rather than instantiating it. If it is not well formed, then this breaks compilation.This originally was necessary to support the copy assignment of transform iterators based upon C++17 lambdas (which are not copy assignable).
This PR provides a possible option for supporting copy assignment for functors lacking copy assignment without this ill-formed copy assignment operator trap.
I would call this a breaking change, as it changes the semantics of copy assignment in a couple ways for a public API tranform_iterator.
Both of these are rare corner cases, but technically may affect existing user codes.