繁体   English   中英

我不能理解语义如何移动到std :: string

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM