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

Vit*_*meo 5 c++ move-semantics c++11

我正在尝试构建一系列可调用对象,以便稍后异步执行。我想尝试以下方法:构建节点的“嵌套”结构(通过将每个节点移动到其“父节点”中),从而生成一个存储所有计算并可以按需启动链的对象。

这就是我的想法:

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?
    }   
};
Run Code Online (Sandbox Code Playgroud)

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

int main()
{
    node n{some_root_callable, []{/*...*/}};
    n.then([]{/*...*/})
     .then([]{/*...*/})
     .then([]{/*...*/})
     .then([]{/*...*/});
}
Run Code Online (Sandbox Code Playgroud)

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

魔盒示例


假设TParentTF、 和TFContinuation是可移动的可调用对象,那么在 的调用期间调用是否安全(即明确定义)std::move(*this)node::then

Gui*_*cot 6

你可以这样做,而且很安全。在大多数情况下,它只会使成员处于未定义但有效的状态。话虽如此,只要您不再尝试使用其成员,移动就是安全的。但对于标准库类型和大多数用户定义的类型,这甚至不会成为问题。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)
    };
}
Run Code Online (Sandbox Code Playgroud)

最棒的是,当它不是右值时,您甚至可以重载它:

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)
    };
}
Run Code Online (Sandbox Code Playgroud)