我有一些将对象移动到另一个对象的代码。我不再需要上层的原始移动物体了。因此,我认为移动是正确的选择。
但是,考虑到安全性,我想知道是否有办法使移动的对象无效,从而防止有人访问时出现未定义的行为。
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
修改:如果没有这样的话,为什么?
答案 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;
}
}