什么构成C ++ 11中“移动”对象的有效状态?

什么构成C ++ 11中“移动”对象的有效状态?

我一直在试图解决C ++ 11中的移动语义应该如何工作,而且我很难理解移动对象需要满足的条件。看看这里的答案并没有真正解决我的问题,因为无法看到如何以合理的方式将它应用于pimpl对象,尽管移动语义的参数非常适合pimpls

我的问题最简单的说明涉及pimpl习语,如下所示:

class Foo {
    std::unique_ptr<FooImpl> impl_;public:
    // Inlining FooImpl's constructors for brevity's sake; otherwise it 
    // defeats the point.
    Foo() : impl_(new FooImpl()) {}

    Foo(const Foo & rhs) : impl_(new FooImpl(*rhs.impl_)) {}

    Foo(Foo && rhs) : impl_(std::move(rhs.impl_)) {}

    Foo & operator=(Foo rhs) 
    {
        std::swap(impl_, rhs.impl_);

        return *this;
    }

    void do_stuff () 
    {
        impl_->do_stuff;
    }};

现在,一旦我离开了,我该怎么办Foo?我可以安全地销毁移动的物体,我可以分配给它,这两者都绝对是至关重要的。但是,如果我尝试do_stuff使用我的Foo,它会爆炸。在我为我的定义添加移动语义之前Foo,每个人都Foo满足了它的不变性do_stuff,而现在已不再是这样了。似乎没有很多很好的替代方案,因为(例如)将移动放入Foo将涉及新的动态分配,这部分地违背了移动语义的目的。我可以检查是否impl_输入do_stuff并将其初始化为默认值FooImpl 如果是,但是这会增加(通常是假的)检查,如果我有很多方法,那就意味着要记住每一个检查。

我应该放弃能够do_stuff成为合理的不变量的想法吗?


人到中年有点甜
浏览 434回答 2
2回答

绝地无双

但是,如果我尝试用我的Foo do_stuff,它会爆炸。是。这样:vector<int>&nbsp;first&nbsp;=&nbsp;{3,&nbsp;5,&nbsp;6};vector<int>&nbsp;second&nbsp;=&nbsp;std::move(first);first.size();&nbsp;&nbsp;//Value&nbsp;returned&nbsp;is&nbsp;undefined.&nbsp;May&nbsp;be&nbsp;0,&nbsp;may&nbsp;not标准使用的规则是将对象保留为有效(意味着对象有效)但未指定状态。这意味着您可以调用的唯一函数是那些对对象的当前状态没有条件的函数。对于vector,您可以使用它的复制/移动赋值运算符,以及clear和empty等几个操作。所以你可以这样做:vector<int>&nbsp;first&nbsp;=&nbsp;{3,&nbsp;5,&nbsp;6};vector<int>&nbsp;second&nbsp;=&nbsp;std::move(first);first.clear();&nbsp;&nbsp;//Cause&nbsp;the&nbsp;vector&nbsp;to&nbsp;become&nbsp;empty.first.size();&nbsp;//Now&nbsp;the&nbsp;value&nbsp;is&nbsp;guaranteed&nbsp;to&nbsp;be&nbsp;0.对于您的情况,复制/移动分配(从任何一方)应该仍然有效,析构函数也应如此。但是你的所有其他功能都有一个基于未被移动的状态的前提条件。所以我没有看到你的问题。如果你想确保没有Pimpl'd类的实例可以为空,那么你将实现适当的复制语义并禁止移动。运动需要物体处于空状态的可能性。
打开App,查看更多内容
随时随地看视频慕课网APP