将 std::move(*this) 放入从 this->some_method 创建的对象中是否安全?

Is it safe to `std::move(*this)` into an object being created from `this->some_method`?

我正在尝试构建一个稍后可以异步执行的可调用对象链。我想尝试以下方法:构建节点 的 "nested" 结构(通过将每个节点移动到它的 "parent") 导致一个对象存储所有计算并可以按需启动链。

这就是我的想法:

template <typename TParent, typename TF>
struct node
{
    TParent _parent;
    TF _f;

    node(TParent&& parent, TF&& f) 
        : _parent{std::move(parent)}, _f{std::move(f)}
    {
    }

    template <typename TFContinuation>
    auto then(TFContinuation&& f_continuation)
    {
        using this_type = node<TParent, TF>;
        return node<this_type, std::decay_t<TFContinuation>>
            {std::move(*this), std::move(f_continuation)};
//           ^^^^^^^^^^^^^^^^
//           ...safe?
    }   
};

上面的代码将允许用户编写如下所示的链:

int main()
{
    node n{some_root_callable, []{/*...*/}};
    n.then([]{/*...*/})
     .then([]{/*...*/})
     .then([]{/*...*/})
     .then([]{/*...*/});
}

(真正的实现会支持更有用的抽象,例如when_all(...)when_any(...)。)

Wandbox example.


假设TParentTFTFContinuation是可移动的可调用对象,是否安全(即明确定义) 在调用 node::then?

期间调用 std::move(*this)

该代码是否存在问题取决于该代码对其获取的引用做了什么。如果调用的代码将对象变成糊状,那么当它 returns 时,您的代码必须处理已变成糊状的对象。但是,对于从成员函数调用的 any 函数,无论它是使用右值引用、可修改的左值引用、指针还是您可能想要的任何其他机制调用的,都是如此想象一下。

你可以做到,而且很安全。在大多数情况下,它只会让成员处于未定义但有效的状态。话虽如此,移动 this 是安全的,只要您不再尝试使用它的成员。但是对于标准库类型和大多数用户定义的类型,这甚至都不是问题。

有一件事我想改变。我只允许从右值调用:

template <typename TFContinuation> //      v-- notice the && here.
auto then(TFContinuation&& f_continuation) && {
    using this_type = node<TParent, TF>;

    return node<this_type, std::decay_t<TFContinuation>>{
        std::move(*this), std::move(f_continuation)
    };
}

很棒的是你甚至可以在它不是右值时重载它:

template <typename TFContinuation>
auto then(TFContinuation&& f_continuation) const & {
    using this_type = node<TParent, TF>;

    return node<this_type, std::decay_t<TFContinuation>>{
        *this, std::move(f_continuation)
    };
}