对于非空字符串,data() 是否保证等于 &front()?



我经常使用std::string作为通用二进制缓冲区。这会导致在获取可变数据指针时出现问题,因为当字符串s为空时不能使用&s.front()

这就是为什么我有这个助手函数(它首先做字符串::data应该做的事情):

char* data(string& s)
{
    if (!s.empty())
        return &s.front();
    else
        return const_cast<char*>(s.data());
}

这与标准一致,因为字符串是连续存储的,不允许覆盖终止的0字符。

我喜欢它,因为它的尺寸检查似乎得到了优化。

但我更喜欢这个功能:

char* data(string& s)
{
    return const_cast<char*>(s.data());
}

我只是不确定这样做是否真的合法。

毫无疑问,它会起作用,如果尺寸检查没有得到优化,我会使用这个版本。

我认为有一个怪癖没有被注意到。这似乎是一个极端的边缘案例,我只是通过仔细阅读才发现的。string::data保证它返回的缓冲区包含字符串和一个空终止符。然而,std::string并不保证其缓冲区具有空终止符。

因此,我认为一个技术兼容的实现不能在创建字符串或调用string::front时添加null终止符,而只能在调用string::datastring::c_str时添加。

因此,即使你得到的指针是相同的,我也不确定副作用是否保证是一样的,这使得这些副作用不一定相等。(在有人问这将如何在const字符串上工作之前,我不明白为什么一个确认实现不能声明内部缓冲区mutable并修改null,即使对于const函数,假设它执行了适当的锁定以确保同时访问安全。)

然而,一个真正做到这一点的实施似乎要么设计得非常糟糕,要么非常残忍。

标准说data() == &operator[](0),它是引用第一个字符的地址。CCD_ 12也等价于CCD_。operator[](0)返回对第一个字符的引用,所以它是否恒定并不重要,它们的地址必须相等。

但现在我不完全确定是否真的允许您通过返回的指针修改字符串(尽管现在我知道它指向可修改的数据)。我几乎可以肯定你可以,因为函数引用了一个非约束引用,但如果我不能弄清楚,那就另当别论了。

令人难以置信的是,在这样一个简单的单行函数中包含了如此多的微妙之处。

最新更新