130

c_str()我已经阅读了几个地方,和data()(在 STL 和其他实现中)之间的区别在于c_str()它总是以空值终止,而data()不是。据我在实际实现中所见,它们要么做同样的事情,要么data()调用c_str().

我在这里想念什么?在哪些场景中使用哪个更正确?

4

6 回答 6

129

文档是正确的。c_str()如果您想要一个以空字符结尾的字符串,请使用。

如果实现者碰巧data()按照c_str()您的方式实现,则不必担心,data()如果您不需要字符串为空终止,则仍然使用,在某些实现中它可能会比 c_str() 执行得更好。

字符串不一定必须由字符数据组成,它们可以由任何类型的元素组成。在那些情况下data()更有意义。c_str()在我看来,只有当你的字符串元素是基于字符的时才真正有用。

额外:从 C++11 开始,两个函数必须相同。iedata现在需要以空值结尾。根据cppreference:“返回的数组以空值结尾,即 data() 和 c_str() 执行相同的功能。”

于 2008-10-11T21:01:15.550 回答
34

C++11/C++0xdata()中,c_str()不再不同。因此data(),最后也需要有一个空终止。

21.4.7.1basic_string访问器 [string.accessors]

const charT* c_str() const noexcept;

const charT* data() const noexcept;

1 返回: 一个指针 p 使得p + i == &operator[](i)对于每个iin [0,size()]


21.4.5 basic_string 元素访问 [string.access]

const_reference operator[](size_type pos) const noexcept;

1 要求:pos <= size()。2 返回:*(begin() + pos) if pos < size(),否则对 T 类型对象的charT();引用,其值不应被修改。

于 2012-09-13T04:41:20.793 回答
20

即使知道您已经看到它们做了同样的事情,或者 .data() 调用了 .c_str(),但假设其他编译器也会出现这种情况是不正确的。您的编译器也可能会随着未来的版本而改变。

使用 std::string 的 2 个理由:

std::string 可用于文本和任意二进制数据。

//Example 1
//Plain text:
std::string s1;
s1 = "abc";

//Example 2
//Arbitrary binary data:
std::string s2;
s2.append("a\0b\0b\0", 6);

当您将字符串用作示例 1 时,您应该使用 .c_str() 方法。

当您使用字符串作为示例 2 时,您应该使用 .data() 方法。不是因为在这些情况下使用 .c_str() 是危险的,而是因为更明确的是您正在使用二进制数据以供其他人查看你的代码。

使用 .data() 的可能陷阱

以下代码是错误的,可能会导致您的程序出现段错误:

std::string s;
s = "abc";   
char sz[512]; 
strcpy(sz, s.data());//This could crash depending on the implementation of .data()

为什么实现者让 .data() 和 .c_str() 做同样的事情很常见?

因为这样做效率更高。使 .data() 返回非空终止的唯一方法是让 .c_str() 或 .data() 复制它们的内部缓冲区,或者只使用 2 个缓冲区。拥有一个空终止缓冲区总是意味着您在实现 std::string 时总是可以只使用一个内部缓冲区。

于 2008-10-11T21:12:22.267 回答
3

已经回答了,一些关于目的的注释:实施自由。

std::string操作——例如迭代、连接和元素突变——不需要零终止符。除非您将 传递string给期望以零结尾的字符串的函数,否则可以将其省略。

这将允许实现让子字符串共享实际字符串数据:string::substr可以在内部保存对共享字符串数据和开始/结束范围的引用,避免复制(和额外分配)实际字符串数据。该实现将推迟复制,直到您调用c_str或修改任何字符串。如果只是读取所涉及的子字符串,则不会制作任何副本。

(写时复制的实现在多线程环境中并不好玩,加上典型的内存/分配节省不值得今天更复杂的代码,所以很少这样做)。


类似地,string::data允许不同的内部表示,例如绳索(字符串段的链表)。这可以显着改进插入/替换操作。c_str同样,当您调用或时,必须将段列表折叠为单个段data

于 2012-07-01T08:04:28.317 回答
2

引用自ANSI ISO IEC 14882 2003(C++03 标准):

    21.3.6 basic_string string operations [lib.string.ops]

    const charT* c_str() const;

    Returns: A pointer to the initial element of an array of length size() + 1 whose first size() elements
equal the corresponding elements of the string controlled by *this and whose last element is a
null character specified by charT().
    Requires: The program shall not alter any of the values stored in the array. Nor shall the program treat the
returned value as a valid pointer value after any subsequent call to a non-const member function of the
class basic_string that designates the same object as this.

    const charT* data() const;

    Returns: If size() is nonzero, the member returns a pointer to the initial element of an array whose first
size() elements equal the corresponding elements of the string controlled by *this. If size() is
zero, the member returns a non-null pointer that is copyable and can have zero added to it.
    Requires: The program shall not alter any of the values stored in the character array. Nor shall the program
treat the returned value as a valid pointer value after any subsequent call to a non- const member
function of basic_string that designates the same object as this.
于 2011-10-05T13:04:42.587 回答
2

之前的所有评论都是一致的,但我还想补充一点,从 c++17 开始,str.data() 返回一个 char* 而不是 const char*

于 2019-02-25T18:23:17.417 回答