2
std::string t1("aaa");
const char *p = t1.c_str();
std::string t2(std::move(t1));
if (p == t2.c_str()) {
    std::cout << "ok!" << std::endl;    
}

此代码在 vs2012 中没有打印任何内容。它只是在memmove内部使用将字符串复制t1t2. 为什么?

4

3 回答 3

9

形式上,正如 jrok 所指出的,您所做的是未定义的行为,因此无论实现做什么,您都无权抱怨。实际上,这将取决于实施。该标准不要求移动构造函数对std::string源字符串做任何事情。如果实现使用小字符串优化(例如 VC++),并且字符串足够小以符合条件,那么它 除了memcpy 字符之外别无他法;他们在一个char[]在字符串对象本身中。CoW 实现(如 g++ 中的实现)可能与它在复制构造函数中所做的没有什么不同,因为它不值得费心;你不会真正节省太多。(但它可能,因为只是交换指针会节省一点。)

我刚刚在 VC++ 中尝试了同样的事情,但使用了 100 个字符的字符串。它进行了交换(并且两个指针相等)。因此 VC++ 的行为取决于字符串是否足够小以供 SSO 应用。G++ 在所有情况下都可以交换。

于 2013-08-15T10:32:56.233 回答
3

Visualtudio在真正移动指针之前比较字符串的长度,通过调试std::move代码,它显示它复制长度小于16字节的字符串

void _Assign_rv(_Myt&& _Right)
{   
   // assign by moving _Right
   if (_Right._Myres < this->_BUF_SIZE)  //_BUF_SIZE is 16, comment mine
       _Traits::move(this->_Bx._Buf, _Right._Bx._Buf,
       _Right._Mysize + 1);
   else
   {    // copy pointer
    this->_Getal().construct(&this->_Bx._Ptr, _Right._Bx._Ptr);
    _Right._Bx._Ptr = pointer();
    }
    this->_Mysize = _Right._Mysize;
    this->_Myres = _Right._Myres;
    _Right._Tidy();
}
于 2013-08-15T10:24:18.110 回答
1

具体来说,这里发生的是“小字符串优化”。

Visual C++ 的 STL(和许多其他)具有“胖”std::string类,可以在内部保存一个小字符串,而所需的内存分配为零。这是针对一些常见用例的优化。

即使使用std::move, 因为您的字符串足够小,以至于它完全存储在std::string自身内部,因此必须复制。如果您尝试使用更大的字符串,您的代码可能会起作用,但绝对不能保证它会起作用,而且您不应该依赖这种行为。

基本上认为std::string这些实现中的 a 类似于:

class string {
 // space for small strings; only used if _external is nullptr
 char  _local[16];
 // pointer to heap-allocated memory; if nullptr, the string is stored in _local
 char* _external;

 // stores a string using small-string optimization is appropriate
 void store(char* src) {
   if (std::strlen(src) < sizeof(_local)) {
     // small string, store in our local buffer and set _external to nullptr
     std::strcpy(_local, src);
     delete _external;
     _external = nullptr;
   } else if (src != _external) {
     // large string, allocate space in heap
     delete _external;
     _external = new char[std::strlen(src) + 1];
     std::strcpy(_external, src);
   }
 }

public:
 // assign a C string to this string
 string(char* src) : _external(nullptr) { store(src); }
 string& operator=(char* src) { store(src); return *this; }

 // be sure to properly use either _local or _external pointer
 char* c_str() { return _external ? _external : _local; }
 bool empty() const { return c_str()[0] == 0; }
};
于 2013-08-15T18:52:30.150 回答