简体   繁体   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)) { ... }

Full source code 完整的源代码

I've made a constructor takes argument with move semantics. 我已经让构造函数接受了带有移动语义的参数。 ( p_str -> m_str ) For a closer look, I opened the library header file basic_string.h but there is one thing that I can't understand. 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);
 }

This is move constructor of basic_string class. 这是basic_string类的move构造函数。 After (#) is executed, p_str turns to ".\\000\\000\\000\\000\\000\\000\\000..." . 执行(#)后, p_str变为".\\000\\000\\000\\000\\000\\000\\000..." As I know, basic_string stores strings in the array _M_local_buf and method _M_local_data() returns its address. 据我所知, basic_string将字符串存储在数组_M_local_buf ,方法_M_local_data()返回其地址。

Then, why __str._M_data(__str._M_local_data()); 然后,为什么要使用__str._M_data(__str._M_local_data()); changes p_str to zero-filled string? p_str更改为零填充字符串? Isn't p_str ( __str ) still having the original strings? 是不是p_str__str )仍具有原始字符串?

What you're seeing is short string optimization. 您所看到的是短字符串优化。

libstdc++'s std::string implementation has two places it can store string data. libstdc ++的std::string实现有两个位置可以存储字符串数据。 It stores long strings in a dynamically allocated array of char s. 它将长字符串存储在动态分配的char数组中。 To avoid the overhead of allocating that array, it can also store short strings in the space it usually uses to track the size of that dynamically allocated array. 为了避免分配该数组的开销,它还可以在通常用来跟踪该动态分配的数组的大小的空间中存储短字符串。 That's _M_local_data . 那是_M_local_data

_M_dataplus._M_p holds a pointer to the first element of whicherver buffer is currently in use. _M_dataplus._M_p持有一个指向当前正在使用的哪个缓冲区的第一个元素的指针。 That's the pointer that _M_data() returns, and the pointer that _M_data(pointer) sets. 那是_M_data()返回的指针, _M_data(pointer)设置的_M_data(pointer)

So putting that together, doing 所以放在一起,做

__str._M_data(__str._M_local_data());
__str._M_set_length(0);

is telling the moved-from string "Forget about any buffer you were previously managing, start using your local buffer for storage, and assume you hold no data". 告诉移出的字符串“忘记以前管理的任何缓冲区,开始使用本地缓冲区进行存储,并假设您不保存任何数据”。


Then, why __str._M_data(__str._M_local_data()); 然后,为什么要使用__str._M_data(__str._M_local_data()); changes p_str to zero-filled string? p_str更改为零填充字符串?

It doesn't. 没有。 It changes p_str 's data pointer to point to the memory that previously held the size of its externally-allocated array. 它将p_str的数据指针更改为指向以前保持其外部分配数组大小的内存。 What you're seeing are the leftovers of that capacity (Did p_str have a capacity of 46 by chance? That's the ASCII code point for '.' ). 您看到的是该容量的剩余容量( p_str是否有46的偶然容量?这是'.'的ASCII代码点)。 For the moment between those two lines, p_str is in an inconsistent state. 在这两行之间的时刻, p_str处于不一致状态。 Its size is still set to its previous size, but the buffer it now points to doesn't hold that number of characters. 它的大小仍然设置为以前的大小,但是它现在指向的缓冲区不包含该数量的字符。 That gets rectified on the next line when the move constructor sets its length to 0 . 当移动构造函数将其长度设置为0时,可以在下一行更正此错误。

Your std::string stores its contents in one of two ways: 您的std::string通过以下两种方式之一存储其内容:

  • If the string is short, it is stored directly in _M_local_buf , which is presumably an array member of std::string (and also accessible via _M_local_data() ). 如果字符串较短,则将其直接存储在_M_local_buf ,该std::string可能是std::string的数组成员(也可以通过_M_local_data()访问)。
  • If the string is long, a char array is allocated separately and a pointer to it is stored in _M_p (which is also accessible via _M_data() ). 如果字符串长,则将单独分配一个char数组,并将其指针存储在_M_p (也可以通过_M_data()访问)。

The if statement deals with the two possible representations: if语句处理两种可能的表示形式:

  • If the contents are stored directly in the std::string object ( __str._M_is_local() ), we copy the data into our own _M_local_buf array. 如果内容直接存储在std::string对象( __str._M_is_local() )中,则将数据复制到我们自己的_M_local_buf数组中。
  • Otherwise we simply copy the pointer (as returned by _M_data() ) and capacity. 否则,我们只复制指针(由_M_data()返回)和容量。

    Right now our objects are in an inconsistent state: Both this->_M_data() and __str._M_data() point to the same allocated storage; 现在,我们的对象处于不一致状态: this->_M_data()__str._M_data()指向同一分配的存储; they both "own" it. 他们都“拥有”它。 To resolve this situation, we need to reset __str so it won't try to free our string data out from under us when it is destroyed. 要解决这种情况,我们需要重置__str以便在销毁字符串数据时不会尝试将其从我们下面释放出来。 We'll do that in a second. 我们将在一秒钟内完成。

_M_length(__str.length()); copies over the length value from __str . __str复制长度值。

__str._M_data(__str._M_local_data()); makes _M_p point to the internal array that is part of the __str object. 使_M_p指向__str对象的内部数组。 If __str wasn't a short string to begin with, this array contains garbage. 如果__str开头不是短字符串,则此数组包含垃圾。 But that doesn't matter, because: 但这没关系,因为:

__str._M_set_length(0) resets the length of __str to 0. The contents of __str._M_local_buf don't matter because 0 of them are "valid", ie part of the string. __str._M_set_length(0)__str的长度重置为0 __str._M_local_buf的内容无关紧要,因为其中0个为“有效”,即字符串的一部分。

In short: This move constructor copies the member variables of __str into our new object, then makes __str an empty string. 简而言之:此move构造函数将__str的成员变量复制到我们的新对象中,然后使__str为空字符串。 (The string contents have been "moved" from __str into *this , so now __str is empty.) (字符串内容已从__str “移动”到*this ,所以现在__str为空。)

This is a general principle: Moving from a variable destroys its contents. 这是一个基本原则:从变量移出会破坏其内容。 It will be a valid object (a valid std::string in this case), but you cannot rely on any data still being there. 这将是一个有效的对象(在这种情况下为有效的std::string ),但是您不能依赖仍然存在的任何数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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