[英]I can't underestand how move semantics work to std::string
explicit Foo(std::string p_str) : m_str(std::move(p_str)) { ... }
我已经让构造函数接受了带有移动语义的参数。 ( p_str
> m_str
)为了更仔细地看,我打开了库头文件basic_string.h
但是有一点我不明白。
basic_string(basic_string&& __str) noexcept :
_M_dataplus(_M_local_data(), std::move(__str._M_get_allocator())) {
if (__str._M_is_local()) {
traits_type::copy(_M_local_buf, __str._M_local_buf, _S_local_capacity + 1);
} else {
_M_data(__str._M_data());
_M_capacity(__str._M_allocated_capacity);
}
_M_length(__str.length());
__str._M_data(__str._M_local_data()); // (#)
__str._M_set_length(0);
}
这是basic_string
类的move构造函数。 执行(#)
后, p_str
变为".\\000\\000\\000\\000\\000\\000\\000..."
。 据我所知, basic_string
将字符串存储在数组_M_local_buf
,方法_M_local_data()
返回其地址。
然后,为什么要使用__str._M_data(__str._M_local_data());
将p_str
更改为零填充字符串? 是不是p_str
( __str
)仍具有原始字符串?
您所看到的是短字符串优化。
libstdc ++的std::string
实现有两个位置可以存储字符串数据。 它将长字符串存储在动态分配的char
数组中。 为了避免分配该数组的开销,它还可以在通常用来跟踪该动态分配的数组的大小的空间中存储短字符串。 那是_M_local_data
。
_M_dataplus._M_p
持有一个指向当前正在使用的哪个缓冲区的第一个元素的指针。 那是_M_data()
返回的指针, _M_data(pointer)
设置的_M_data(pointer)
。
所以放在一起,做
__str._M_data(__str._M_local_data());
__str._M_set_length(0);
告诉移出的字符串“忘记以前管理的任何缓冲区,开始使用本地缓冲区进行存储,并假设您不保存任何数据”。
然后,为什么要使用
__str._M_data(__str._M_local_data());
将p_str
更改为零填充字符串?
没有。 它将p_str
的数据指针更改为指向以前保持其外部分配数组大小的内存。 您看到的是该容量的剩余容量( p_str
是否有46
的偶然容量?这是'.'
的ASCII代码点)。 在这两行之间的时刻, p_str
处于不一致状态。 它的大小仍然设置为以前的大小,但是它现在指向的缓冲区不包含该数量的字符。 当移动构造函数将其长度设置为0
时,可以在下一行更正此错误。
您的std::string
通过以下两种方式之一存储其内容:
_M_local_buf
,该std::string
可能是std::string
的数组成员(也可以通过_M_local_data()
访问)。 char
数组,并将其指针存储在_M_p
(也可以通过_M_data()
访问)。 if
语句处理两种可能的表示形式:
std::string
对象( __str._M_is_local()
)中,则将数据复制到我们自己的_M_local_buf
数组中。 否则,我们只复制指针(由_M_data()
返回)和容量。
现在,我们的对象处于不一致状态: this->_M_data()
和__str._M_data()
指向同一分配的存储; 他们都“拥有”它。 要解决这种情况,我们需要重置__str
以便在销毁字符串数据时不会尝试将其从我们下面释放出来。 我们将在一秒钟内完成。
_M_length(__str.length());
从__str
复制长度值。
__str._M_data(__str._M_local_data());
使_M_p
指向__str
对象的内部数组。 如果__str
开头不是短字符串,则此数组包含垃圾。 但这没关系,因为:
__str._M_set_length(0)
将__str
的长度重置为0 __str._M_local_buf
的内容无关紧要,因为其中0个为“有效”,即字符串的一部分。
简而言之:此move构造函数将__str
的成员变量复制到我们的新对象中,然后使__str
为空字符串。 (字符串内容已从__str
“移动”到*this
,所以现在__str
为空。)
这是一个基本原则:从变量移出会破坏其内容。 这将是一个有效的对象(在这种情况下为有效的std::string
),但是您不能依赖仍然存在的任何数据。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.