我对 std::move()
如何真正清空某些东西有些困惑。
我写了一些代码:
int main()
{
string str1("this is a string");
std::cout<<std::boolalpha<<str1.empty()<<std::endl;
string str2(std::move(str1));
cout<<"str1: "<<str1.empty()<<endl;
cout<<"str2: "<<str2.empty()<<endl;
}
输出为:
假
true//这意味着原始字符串被清空
假
为什么每次都是原来的字符串被清空? 我读过一些关于 move 语义的资料,包括它的原始提案(this one),其中说:
The difference between a copy and a move is that a copy leaves the source unchanged. A move on the other hand leaves the source in a state defined differently for each type. The state of the source may be unchanged, or it may be radically different. The only requirement is that the object remain in a self consistent state (all internal invariants are still intact). From a client code point of view, choosing move instead of copy means that you don't care what happens to the state of the source.
所以,根据这句话,上面的str1的原始内容应该是某种未定义。但为什么每次move()
都会被清空呢? (实际上我已经在 std::string
和 std::vector
上测试了这种行为,但结果是相同的。)
为了了解更多信息,我定义了自己的字符串类来测试,如下所示:
class mstring
{
private:
char *arr;
unsigned size;
public:
mstring():arr(nullptr),size(0){}
mstring(char *init):size(50)
{
arr = new char[size]();
strncpy(arr,init,size);
while(arr[size-1] != '\0') //simply copy
{
char *tmp = arr;
arr = new char[size+=50]();
strncpy(arr,tmp,50);
delete tmp;
strncpy(arr-50,init+(size-50),50);
}
}
bool empty(){ return size==0;}
}
做同样的事情:
int main()
{
mstring str("a new string");
std::cout<<std::boolalpha<<str.empty()<<std::endl;
mstring anotherStr(std::move(str));
std::cout<<"Original: "<<str.empty()<<std::endl;
std::cout<<"Another: "<<anotherStr.empty()<<std::endl;
}
输出为:
假
Original: flase//表示原来的字符串还在
另一个:错误
即使我添加了这样的 move 构造函数:
mstring(mstring&& rvalRef)
{
*this = rvalRef;
}
结果还是一样。
我的问题是:为什么 std::string
被清空,但我的自定义却没有?
最佳答案
因为这就是 std::string
move 构造函数的实现方式。它获取旧字符串内容的所有权(即动态分配的 char
数组),而旧字符串什么也没有留下。
另一方面,您的 mstring
类实际上并未实现 move 语义。它有一个 move 构造函数,但它所做的只是使用 operator=
复制字符串。更好的实现是:
mstring(mstring&& rvalRef): arr(rvalRef.arr), size(rvalRef.size)
{
rvalRef.arr = nullptr;
rvalRef.size = 0;
}
这会将内容传输到新字符串,并使旧字符串保持与默认构造函数创建它时相同的状态。这避免了分配另一个数组并将旧数组复制到其中的需要;相反,现有数组只是获得了新的所有者。
关于c++ - 在 std::move() 之后使字符串为空的机制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34782270/