C++ std::move-std::string-内部指针
我很惊讶s和s2指向“sample”的内部指针不相等,这是什么解释C++ std::move-std::string-内部指针,c++,string,move,C++,String,Move,我很惊讶s和s2指向“sample”的内部指针不相等,这是什么解释 #include <string> #include <cassert> int main() { std::string s("sample"); std::string s2(std::move(s)); assert( reinterpret_cast<int*>(const_cast<char*>(s.data())) ==
#include <string>
#include <cassert>
int main()
{
std::string s("sample");
std::string s2(std::move(s));
assert(
reinterpret_cast<int*>(const_cast<char*>(s.data())) ==
reinterpret_cast<int*>(const_cast<char*>(s2.data()))
); // assertion failure here
return 1;
}
#包括
#包括
int main()
{
std::字符串s(“样本”);
std::string s2(std::move(s));
断言(
重新解释强制转换(常量强制转换(s.data())==
重新解释强制转换(const强制转换(s2.data())
);//此处的断言失败
返回1;
}
为什么你认为它们应该是一样的?您正在使用其移动构造函数从s
构造s2
。这将数据所有权从s
转移到s2
,并使s
处于“空”状态。该标准没有详细说明这需要什么,但在此之后访问s
的数据(不首先重新分配)是未定义的
string
的简化(且不完整)版本如下所示:
class string {
char* buffer;
public:
string(char const* from)
: buffer(new char[std::strlen(from) + 1])
{
std::strcpy(buffer, from);
}
string(string&& other)
: buffer(other.buffer)
{
other.buffer = nullptr; // (*)
}
~string() {
delete[] buffer;
}
char const* data() const { return buffer; }
};
我希望这能说明
data()
成员不相等的原因。如果我们省略了(*)
标记的行,我们将删除main
末尾的内部缓冲区两次:一次用于s
,一次用于s2
。重置buffer
指针可确保不会发生这种情况。每个std::string
都有自己指向的缓冲区。您从另一个移动了一个缓冲区,但这并不意味着它共享一个缓冲区。初始化s2
时,它从s
接管缓冲区,并成为该缓冲区的所有者。为了避免s
拥有同一个缓冲区,它只需将s
的缓冲区设置为一个新的空缓冲区(现在由s
负责)
从技术上讲,还涉及到一些优化,很可能没有为空字符串或非常小的字符串显式分配真正的缓冲区,但是std::string
的实现将使用std::string
内存本身的一部分。这通常被称为STL中的小字符串优化
还要注意的是,
s
已被移开,因此您的代码对其数据的访问是非法的,这意味着它可能返回任何内容。在将其值替换为某些已知值之前,您不应使用从移动的字符串
:
库代码需要在参数中保留有效值,但除非类型或函数文档另有说明,否则对结果参数值没有其他约束。这意味着通常最明智的做法是避免再次使用moved-from参数。如果必须再次使用它,请确保在执行此操作之前使用已知值重新初始化它
库可以将它想要的任何东西粘贴到字符串中,但很可能最终会得到一个空字符串。这就是运行一台计算机所产生的结果。然而,人们不应该期望在“已从”对象中找到任何特别的内容。顺便说一句,为什么要强制转换?他们什么也不做
s.data()==s2.data()
将是相同的。因为我已经开始打印地址,并在第二次切换到断言。。。忘了像你写的那样简化它