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

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

本文关键字:method 创建 some 安全 是否 gt 对象 this- move std this      更新时间:2023-10-16

我试图建立一个可调用的对象链,可以稍后异步执行。我想尝试以下方法:构建一个节点的"嵌套"结构(通过将每个节点移动到它的"父节点"中),从而产生一个存储所有计算的对象,并且可以根据需要启动链。

这就是我的想法:

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(...))

<<p> Wandbox例子/strong>。

假设TParentTFTFContinuation为可移动可调用对象,是否安全?

在调用node::then时调用std::move(*this)

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

有一件事我要改变。我只允许从右值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)
    };
}

代码中是否存在问题取决于该代码如何处理它所获得的引用。如果被调用的代码将对象转换成糊状,那么当它返回时,您的代码必须处理已转换成糊状的对象。但是对于任何从成员函数中调用的函数都是如此,无论它是使用右值引用、可修改的左值引用、指针还是您可能想到的任何其他机制调用。