有没有办法让移动的对象"无效"?

时间:2015-10-11 12:02:12

标签: c++11 move move-semantics

我有一些将对象移动到另一个对象的代码。我不再需要上层的原始移动物体了。因此,我认为移动是正确的选择。

但是,考虑到安全性,我想知道是否有办法使移动的对象无效,从而防止有人访问时出现未定义的行为。

Here就是一个很好的例子:

// move example
#include <utility>      // std::move
#include <vector>       // std::vector
#include <string>       // std::string

int main () {
  std::string foo = "foo-string";
  std::string bar = "bar-string";
  std::vector<std::string> myvector;

  myvector.push_back (foo);                    // copies
  myvector.push_back (std::move(bar));         // moves

  return 0;
}

描述说:

  

第一次拨打myvector.push_back会将foo的值复制到。{1}}   向量(foo保留调用之前的值)。第二个电话   将bar的值移动到向量中。这会转移其内容   进入向量(bar失去它的值,现在是有效的但是   未指明的状态)。

有没有办法使bar无效,以至于访问它会导致编译错误?类似的东西:

myvector.push_back (std::move(bar));         // moves
invalidate(bar); //something like bar.end() will then result in a compiler error

修改:如果没有这样的话,为什么

3 个答案:

答案 0 :(得分:1)

访问移动的对象不是未定义的行为。移动的对象仍然是有效对象,并且程序可能非常希望继续使用所述对象。例如,

template< typename T >
void swap_by_move(T &a, T &b)
{
    using std::move;
    T c = move(b);
    b = move(a);
    a = move(c);
}

答案 1 :(得分:1)

更大的答案是因为移动或不移动是在运行时做出的决定,并且给出编译时错误是在编译时做出的决定。

foo(bar); // foo might move or not
bar.baz(); // compile time error or not?

它无法正常运行..您可以在编译时分析中进行近似,但是对于开发人员而言,会出现错误或为保持有效的程序而做任何有用的事情,或者开发人员必须对被调用的函数进行烦人且易碎的注释,以保证不会移动参数。

换句话说,如果使用包含值42的整数变量,则询问是否存在编译时错误。或者如果使用包含空指针值的指针。您可能成功地使用clang分析API实现了一个近似的构建时代码约定检查器,然而,如果您不能证明std::move没有被证明{C} AST的CFG,则会出错直到给定使用变量为止。

答案 2 :(得分:0)

移动语义就是这样,所以你可以在任何它的正确状态下得到一个对象。正确的状态意味着所有字段都具有正确的值,并且所有内部不变量仍然良好。这样做是因为在移动之后你实际上并不关心移动对象的内容,但资源管理,赋值和析构函数之类的东西应该可以正常工作。 所有STL类(以及所有STL类都使用默认移动构造函数/赋值)只是将其内容与新内容交换,因此两个状态都是正确的,并且它非常容易实现,快速且方便。

您可以定义具有isValid字段的类,该字段通常为true且在移动时(即在移动构造函数/移动赋值中)将其设置为false。然后,您的对象将正确状态我无效。只是不要忘记在需要的地方检查它(析构函数,赋值等)。

isValid字段可以是具有空值的一个指针。关键是:你知道,移动后该对象处于可预测状态,而不仅仅是内存中的随机字节。

修改:String的示例:

class String {
public:
    string data;
private:
    bool m_isValid;

public:
    String(string const& b): data(b.data), isValid(true) {}

    String(String &&b): data(move(b.data)) {
        b.m_isValid = false;
    }

    String const& operator =(String &&b) {
        data = move(b.data);
        b.m_isValid = false;
        return &this;
    }

    bool isValid() {
        return m_isValid;
    }
}