[PATCH] D55045: Add a version of std::function that includes a few optimizations.

Louis Dionne via Phabricator reviews at reviews.llvm.org
Wed Dec 5 06:51:08 PST 2018


ldionne added inline comments.


================
Comment at: include/functional:2237
 {
-    *this = nullptr;
-    if (__f.__f_ == 0)
-        __f_ = 0;
-    else if ((void *)__f.__f_ == &__f.__buf_)
-    {
-        __f_ = __as_base(&__buf_);
-        __f.__f_->__clone(__f_);
-    }
-    else
-    {
-        __f_ = __f.__f_;
-        __f.__f_ = 0;
+    if (&__f != this) {
+        *this = nullptr;
----------------
jsoyke wrote:
> sbenza wrote:
> > ldionne wrote:
> > > sbenza wrote:
> > > > ldionne wrote:
> > > > > We didn't check for that before, did we? IOW the implementation worked transparently even in the case of a self move-assignment. Would it be possible to retain that property (and save this check in the current implementation)?
> > > > Without this check the code is equally correct, as in the moved-from value has a valid-but-unspecified state. The lhs happens to also be the moved-from value, but that is fine.
> > > Rephrasing to make sure I understand: If `this == &__f`, then after the assignment `__f` is in a valid-but-unspecified state (in this case it is empty). Since `this == &__f`, `*this` is also in the same valid-but-unspecified state.
> > > 
> > > I don't think this makes sense for self-assignment, because the `lhs` is usually understood to contain the value of the `rhs` after a move-assignment. IOW, the following should hold:
> > > 
> > > ```
> > > T x = ...;
> > > T copy = x;
> > > T y = std::move(x);
> > > assert(y == copy);
> > > ```
> > > 
> > > This is not the case here.
> > > 
> > The example above does not have any self-assignment (or any assignment).
> > 
> > My argument is that `y = std::move(y);` leaves `y` in an unspecified state. It is not required to be a noop. This is how it behaves today and it is up to spec.
> Self move assignment left the function empty before, preserving that behavior now.
Yeah, my example is obviously broken. What I meant is just that one would expect the `lhs` to contain the value of the `rhs`, not for that value to be nuked.

I understand the current implementation is valid in terms of the specification. I'm saying the specification does not satisfy the principle of least surprise. Leave it as-is.


================
Comment at: test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp:68
     std::function<FuncType> f2(std::allocator_arg, alloc, target);
-    assert(globalMemCounter.checkOutstandingNewEq(0));
+    assert(globalMemCounter.checkOutstandingNewEq(0) ||
+           globalMemCounter.checkOutstandingNewEq(1));
----------------
Should these checks be made to depend on `#ifdef _LIBCPP_ABI_OPTIMIZED_FUNCTION`?


================
Comment at: test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_rfunction.pass.cpp:92
         assert(f2.target<Ref>());
-        assert(f.target<Ref>()); // f is unchanged because the target is small
+        // assert(f.target<Ref>()); // f is unchanged because the target is small
     }
----------------
Those asserts should be removed too.


Repository:
  rCXX libc++

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55045/new/

https://reviews.llvm.org/D55045





More information about the libcxx-commits mailing list