我经常使用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::data
或string::c_str
时添加。
因此,即使你得到的指针是相同的,我也不确定副作用是否保证是一样的,这使得这些副作用不一定相等。(在有人问这将如何在const
字符串上工作之前,我不明白为什么一个确认实现不能声明内部缓冲区mutable
并修改null,即使对于const
函数,假设它执行了适当的锁定以确保同时访问安全。)
然而,一个真正做到这一点的实施似乎要么设计得非常糟糕,要么非常残忍。
标准说data() == &operator[](0)
,它是引用第一个字符的地址。CCD_ 12也等价于CCD_。operator[](0)
返回对第一个字符的引用,所以它是否恒定并不重要,它们的地址必须相等。
但现在我不完全确定是否真的允许您通过返回的指针修改字符串(尽管现在我知道它指向可修改的数据)。我几乎可以肯定你可以,因为函数引用了一个非约束引用,但如果我不能弄清楚,那就另当别论了。
令人难以置信的是,在这样一个简单的单行函数中包含了如此多的微妙之处。