【发布时间】:2020-12-23 15:15:07
【问题描述】:
我有点困惑为什么std::move(std::string) 没有将传递的std::string 参数设置为空状态(我的意思是std::string 的大小为0,并且它的内部缓冲区在调用std::move(std::string) 后指向nullptr )。这是一个示例代码
#include <iostream>
#include <string>
void print(std::string& str) {
std::cout << "lref\n";
std::cout << str << "\n" << std::endl;
}
void print(const std::string& str) {
std::cout << "const lref\n";
std::cout << str << "\n" << std::endl;
}
void print(std::string&& str) {
std::cout << "rref\n";
std::cout << str << "\n" << std::endl;
}
int main() {
std::string str_a = "Hello, ";
std::string str_b = "world!";
print(str_a);
print(str_b);
print(str_a + str_b);
print(std::move(str_a));
print(str_a); // was expecting str_a to be empty but still prints Hello,
return 0;
}
【问题讨论】:
-
不应该那样做。被移动的对象应该处于有效但不确定的状态。
-
你预期错了。
std::move只创建一个右值引用,它不会“移动”任何东西——这必须通过移动构造函数或移动赋值来完成。 -
例如,您的实现可能会进行短字符串优化 (SSO),因此甚至不指向缓冲区,只需在内部存储
chars。在这种情况下,没有什么可以释放,也没有双重释放相同(不存在的)缓冲区的危险,所以它不需要清除任何东西。但同样,在实践中它是否这样做并不重要,因为你不应该在移动后使用该对象,除非你首先将它重新分配/重置为已知状态,这样的移动操作不会'不给。 -
即使字符串实际上被移出(因为它在此代码中不是),该字符串仍然是有效的,但未指定状态。我发现这通常是一个很好的期望:如果您
std::move一个对象,则该对象适合重新分配或销毁,仅此而已......对某些类型的对象有一些额外的保证(例如, std::vector 和 std::unique_ptr 和 std::shared_ptr 有更强的保证)。 Howard Hinnant 不喜欢我的“放手”的看法,他会说(转述)从程序员保证的任何状态移动的对象。
标签: c++