std :: move - std :: string - 内部指针

时间:2013-04-07 11:01:24

标签: c++ string move

我很惊讶s和s2内部指针指向"示例"不平等,有什么解释?

#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;
}

3 个答案:

答案 0 :(得分:3)

为什么你认为他们应该是一样的?您正在使用其移动构造函数从s2构建s。这会将数据所有权从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指针可确保不会发生这种情况。

答案 1 :(得分:3)

每个std::string都有自己指向的缓冲区。您从另一个移动的事实不会使它共享一个缓冲区。初始化s2时,它将从s接管缓冲区并成为该缓冲区的所有者。为了避免s“拥有”相同的缓冲区,它只是将s的缓冲区设置为一个新的空缓冲区(现在由s负责)。

从技术上讲,还有一些优化,很可能没有为空字符串或非常小字符串显式分配的实际缓冲区,而是std::string的实现将使用std::string的一部分1}}记忆本身。这通常称为STL中的小字符串优化。

另请注意,s已被移除,因此您的代码访问其数据是非法的,这意味着可以返回任何内容。

答案 2 :(得分:2)

在使用某个已知值替换其值之前,不应使用移动的string

  

库代码需要在参数中保留有效值,但除非类型或函数文档另有说明,否则对结果参数值没有其他约束。这意味着避免再次使用移动参数通常是最明智的。如果必须再次使用它,请确保在执行此操作之前使用已知值重新初始化它。

库可以将任何想要的东西粘贴到字符串中,但很可能你最终会得到一个空字符串。这就是运行example from cppreference产生的东西。但是,人们不应该期望在移动的对象中找到任何特别的东西。