data
提供了新的重载,而没有给c_str
提供。在这一点上,我们只能进行推测(除非参与讨论的人加入进来),但我想提出以下几点供考虑:
即使只是向data
添加重载也会破坏一些代码;保持这个改变的保守性是最小化负面影响的一种方式。
c_str
函数到目前为止完全与data
相同,实际上是用于接口代码的“遗留”设施,该代码采用“C字符串”,即一个不可变的、以null结尾的字符数组。由于你可以随时用data
替换c_str
,所以没有特别的理由添加到这个遗留接口。
我意识到P0292R1的动机是存在错误或由于C原因只采用可变指针的遗留API,即使它们不会发生变化。尽管如此,我想我们不想为字符串已经庞大的API添加更多绝对必要的内容。
还有一点:从C++17开始,只要写入值为零,您现在可以写入空终止符。 (以前,向空终止符写入任何内容都是未定义的行为。)可变的c_str
将创建另一个入口点到这个特定的微妙之处,我们拥有的微妙越少,就越好。
data
重载绝对*破坏了代码。我们应对了,但这不是你想要随意做的事情。 - Kerrek SBdata()
成员函数被重载的原因在于这篇论文中进行了解释。阅读此文章可以了解更多信息。std::string
的非const .data()
成员函数。在调用C库函数时,如果其C字符串参数没有const限定符,使用它也很方便。摘要
std::string
缺乏非const.data()
成员函数是一个疏忽还是基于C++11之前std::string
语义的有意设计?无论哪种情况,这种功能的缺失诱使开发人员在几个合法的场景下使用不安全的替代方式。本文主张为std::string
增加非const.data()
成员函数,以改善标准库的统一性并帮助C++开发人员编写正确的代码。用例
C库有时包括具有char *参数的例程。 Windows API中CreateProcess
函数的lpCommandLine
参数就是一个例子。由于std::string
的data()
成员是const,它不能用于将std :: string对象与lpCommandLine
参数一起使用。开发人员会尝试使用.front()
来代替,例如以下示例。
std::string programName;
// ...
if( CreateProcess( NULL, &programName.front(), /* etc. */ ) ) {
// etc.
} else {
// handle error
}
请注意,当 programName
为空时,programName.front()
表达式会导致未定义的行为。一个临时的空 C-字符串可以修复这个 bug。std::string programName;
// ...
if( !programName.empty() ) {
char emptyString[] = {'\0'};
if( CreateProcess( NULL, programName.empty() ? emptyString : &programName.front(), /* etc. */ ) ) {
// etc.
} else {
// handle error
}
}
如果有一个非const的.data()
成员,就像std::vector
一样,正确的代码将是直截了当的。
std::string programName;
// ...
if( !programName.empty() ) {
char emptyString[] = {'\0'};
if( CreateProcess( NULL, programName.data(), /* etc. */ ) ) {
// etc.
} else {
// handle error
}
}
当调用没有在其C字符串参数上具有const限定符的C库函数时,非常方便的是一个非const .data() std::string
成员函数。这在旧代码和需要与旧的C编译器兼容的代码中很常见。
这取决于“您想对其进行的操作”的语义。 一般来说,std::string
有时被用作缓冲向量,即替代 std::vector<char>
。 这经常在 boost::asio
中见到。 换句话说,它是一个字符数组。
c_str()
:严格意义上意味着您正在寻找以空字符结尾的字符串。 在这种意义上,您不应修改数据,并且您永远不需要将字符串作为非const使用。
data()
:您可能需要将字符串中的信息作为缓冲区数据使用,甚至可以作为非const使用。 您可能需要修改数据,但只要不涉及更改字符串的长度即可执行该操作。
c_str
和data
是完全等价的。 - Kerrek SBdata
来请求空终止符(这可能是你想要暗示的,也可能不是)。完全可以使用data
来明确获取一个以空字符结尾的字符串;我不会建议任何人改用c_str
。 - Kerrek SBdata()
是不好的实践。你不会帮助下一个阅读你代码的人。这是我的观点,无论如何 :-) - The Quantum Physiciststd::string类的两个成员函数c_str和data由于其历史原因而存在。
在C++11之前,std::string可以被实现为写时复制(copy-on-write)。内部表示不需要任何存储字符串的空终止符。成员函数c_str确保返回的字符串以空终止符结尾。成员函数data仅返回指向未必以空终止符结尾的存储字符串的指针。- 为了确保对字符串的更改被注意到以启用写时复制,这两个函数都需要返回const数据的指针。
所有这些都在C++11中发生了变化,因为std::string不再允许使用写时复制。由于c_str仍然需要提供空终止的字符串,因此空终止符总是附加到实际存储的字符串末尾。否则,调用c_str可能需要更改存储的数据以使字符串以空终止符结尾,这将使c_str成为一个非const函数。由于data提供了指向存储字符串的指针,因此它通常与c_str具有相同的实现。这两个函数由于向后兼容性而仍然存在。
c_str
是以空字符结尾有关,而std::string
可能在中间包含空字符,我也希望data()
返回原始缓冲区(无论其中间是否包含空字符)。 - 463035818_is_not_a_numberdata()
有一个重载,而c_str()
没有?我的意思是我们在C++11中使它们同质化,现在我们又区分它们,为什么?这种问题在重复中没有得到回答。然而,这里的答案提供了对我的问题的见解! - gsamaras