返回类型时c_str()与data()

gsa*_*ras 38 c++ string c-str c++17

在C++ 11之后,我想到了c_str()并且data() 等效.

C++ 17为后者引入了一个重载,返回一个非常量指针(引用,我不确定它是否完全在C++ 17中更新):

const CharT* data() const;    (1)   
CharT* data();                (2)   (since C++17)
Run Code Online (Sandbox Code Playgroud)

c_str() 只会返回一个常量指针:

const CharT* c_str() const;
Run Code Online (Sandbox Code Playgroud)

为什么在C++ 17中区分这两种方法,特别是当C++ 11是使它们成为同构的时候?换句话说,为什么只有一种方法过载,而另一种方法没有?

Ker*_* SB 22

P0272R1为C++ 17 添加了新的重载.论文本身和其中的链接都没有讨论为什么只data给予新的重载而c_str不是.我们现在只能推测(除非参与讨论的人员参与讨论),但我想提出以下几点供我们考虑:

  • 即使只是添加过载来data破坏一些代码; 保持这种变化保守是一种减少负面影响的方法.

  • c_str到目前为止,该函数完全相同,data并且实际上是用于连接带有"C字符串"的代码的"遗留"工具,即不可变的,以null结尾的char数组.由于您始终可以替换c_strdata,因此没有特别的理由可以添加到此旧版界面.

我意识到P0292R1的动机是,确实存在遗留的API错误地或出于C原因只采用可变指针,即使它们没有变异.尽管如此,我想我们不想在字符串已经非常庞大的API中添加更多内容.

还有一点:由于C++ 17,你现在允许的空终止,只要你写的值为零.(以前,它曾经是UB向null终止符写入任何东西.)一个mutable c_str会为这个特殊的微妙创建另一个入口点,我们拥有的微妙之处就越少.


P.W*_*P.W 21

本文在open-std.org中data()解释了成员过载的原因.

TL;论文的DR:添加了非const .data()成员函数,std::string以提高标准库的一致性,并帮助C++开发人员编写正确的代码.调用不对其C字符串参数进行const限定的C库函数时也很方便.

论文的一些相关段落:

摘要
std::string的缺乏非const的.data()成员函数的疏忽或故意设计基于预先C++ 11名std::string的语义?在任何一种情况下,缺乏功能都会诱使开发人员在几种合法场景中使用不安全的替代方案.本文主张为.data()std :: string 添加一个非const 成员函数,以提高标准库的一致性,并帮助C++开发人员编写正确的代码.

用例
C库偶尔会包含具有char*参数的例程.一个示例是Windows API lpCommandLine中的CreateProcess函数参数.因为const 的data()成员std::string,它不能用于使std :: string对象与 lpCommandLine参数一起使用.开发人员很想使用.front(),如下例所示.

std::string programName;
// ...
if( CreateProcess( NULL, &programName.front(), /* etc. */ ) ) {
  // etc.
} else {
  // handle error
}
Run Code Online (Sandbox Code Playgroud)

请注意,当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
  }
}
Run Code Online (Sandbox Code Playgroud)

如果存在非const .data()成员,那么std::vector正确的代码将是直截了当的.

std::string programName;
// ...
if( !programName.empty() ) {
  char emptyString[] = {'\0'};
  if( CreateProcess( NULL, programName.data(), /* etc. */ ) ) {
    // etc.
  } else {
    // handle error
  }
}
Run Code Online (Sandbox Code Playgroud)

.data() std::string当调用对其C字符串参数没有const限定的C库函数时,非const 成员函数也很方便.这在较旧的代码和那些需要使用较旧的C编译器可移植的代码中很常见.


The*_*ist 5

它只取决于"你想用它做什么"的语义.一般来说,std::string有时用作缓冲向量,即作为替代std::vector<char>.这可以boost::asio经常看到.换句话说,它是一个字符数组.

c_str():严格意味着您正在寻找以null结尾的字符串.从这个意义上说,你永远不应该修改数据,你永远不应该把字符串作为非const.

data():您可能需要字符串中的信息作为缓冲区数据,甚至是非const.您可能需要也可能不需要修改数据,只要它不涉及更改字符串的长度即可.

  • 我认为空终止是一个红色的鲱鱼.对于空终止,`c_str`和`data`都是绝对等效的. (3认同)
  • @KerrekSB这不是关于是否存在的空终止.从某种意义上说,您是否需要"以null结尾的字符串"或"缓冲区向量",而您不关心空终止. (2认同)
  • @KerrekSB你是对的,但请记住,C++是一种富有表现力的语言,你编写的代码文本理想上应该有意义.我个人认为使用`data()`是不好的做法,如果你想要的只是一个以空字符结尾的字符串.你不会帮助那个接下来读代码的人.这是我的意见,无论如何:-) (2认同)