标准::移动 - 标准::内部指针

std::move - std::internal pointer

本文关键字:标准 指针 内部 移动      更新时间:2023-10-16

我很惊讶s和s2内部指向"sample"的指针不相等,这是什么解释?

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

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

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

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

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

在将其

值替换为某个已知值之前,不应使用移自string

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

库可以将它想要的任何内容粘贴到字符串中,但很可能最终会得到一个空字符串。这就是从 cppreference 运行示例所产生的结果。但是,不应期望在移出对象中找到任何特定内容。

相关文章: