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

时间:2016-11-15 17:39:53

标签: c++ c++11 move-semantics

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

这就是我的想法:

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是可移动的可调用对象,是安全的(即明确定义的)来调用{在调用std::move(*this)

期间{1}}

2 个答案:

答案 0 :(得分:3)

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

有一件事我会改变。我只允许来自rvalue的电话:

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)
    };
}

答案 1 :(得分:0)

该代码中是否存在问题取决于该代码对其获得的引用的作用。如果被调用的代码将对象变为糊状,那么当它返回时,你的代码必须处理一个被变成糊状的对象。但是对于从成员函数调用的任何函数来说都是如此,无论它是使用rvalue引用,可修改的左值引用,指针还是您可能想要的任何其他机制调用。 / p>