移动后左值是否有效?

时间:2017-09-28 14:08:10

标签: c++ move-semantics rvalue

假设我们有以下课程:

class Foo
{
public:
    Foo() { _bar=new Bar };
    Foo(const Foo &right) { _bar=new Bar(right.bar); };
    Foo(Foo &&right) { _bar=right._bar;  right.bar=new Bar(); };

    ~Foo() { delete _bar; }

    Foo &operator=(const Foo &right) { _bar->opertor=(right.bar); return *this;}
    Foo &operator=(Foo &&right) { std::swap(_bar, right._bar); return *this;}

    void func() { _bar->test=1 };

private:
    Bar *_bar;
};

将其更改为以下内容是否合法,并期望最终用户知道在执行移动后rvalue不再有效(在调用除了赋值运算符之外的任何其他内容可能会崩溃)?

class Foo
{
public:
    Foo() { _bar=new Bar };
    Foo(const Foo &right) { _bar=new Bar(right.bar); };
    Foo(Foo &&right) { _bar=right._bar;  right.bar=nullptr; };

    ~Foo() { if(_bar != nullptr) delete _bar; }

    Foo &operator=(const Foo &right) 
    { 
         if(_bar == nullptr) 
             _bar=new Bar();
         _bar->opertor=(right.bar); 
         return *this;
    }

    Foo &operator=(Foo &&right)
    {
        if(_bar != nullptr)
            delete _bar;  
        _bar=right._bar; 
        right._bar=nullptr; 
        return *this;
    }

    void func() { _bar->test=1 };

private:
    Bar *_bar;
};

我担心的是func(以及该类中的所有其他函数)假设_bar存在。

2 个答案:

答案 0 :(得分:0)

  

将其更改为以下内容是否合法,并期望最终用户知道在执行移动后rvalue不再有效?

你当然应该这样做。不应将右值引用保持在可用状态。移动构造函数和移动赋值运算符背后的想法是,您正在移动来自对象的有用数据。我不会使用不再有效的来描述它。从C ++的角度来看,它仍然是一个有效的对象,就像nullptr是一个有效的指针一样。

答案 1 :(得分:0)

您应该记录每个成员函数的Foo前提条件,例如:

void Foo::func();
  

要求: *this未处于移出状态。

然后,您可以选择需要使用Foo::func()的任何客户,除非......

如果您将Foo与需要func()的其他人的图书馆一起使用,并且没有记录“除非处于移动状态”之外的内容,那么您运气不好

例如:假设您的Foooperator<这样:

bool operator<(const Foo& x, const Foo& y);
  

Requries: xy都不属于移出状态。

现在,如果您执行以下操作:

std::vector<Foo> v;
// ... fill v
std::sort(v.begin(), v.end());  // oops!

上面的最后一行要求FooLessThanComparable ,无论Foo是否处于移出状态。这对于s​​td :: lib中的通用代码的 all 都是如此。 std代码的requires子句适用于用户提供的代码,不会为移动的对象设置例外。

但是,如果你的operator<在任一参数处于移动状态时有效,那么对std::sort的调用就可以了。即使func()仍然要求Foo 处于移出状态,也是如此。这是因为std::sort根本不需要func()

总而言之,这完全取决于您的Foo与之互动的其他代码。也许没关系,也许不是。记录Foo的作用,并了解您使用Foo的代码的要求。