繁体   English   中英

为什么 data() 和 c_str() 返回 char const*,而 operator[] 返回 char&?

[英]Why do data() and c_str() return char const*, while operator[] returns char&?

为什么std::string::datastd::string::c_str()返回指向const字符的指针,而std::string::operator[]返回对可变字符的引用?

std::string string("eightfold is the greatest");

auto s = string.data();
*s = 'r'; // illegal

auto t = &string[0];
*t = 'r'; // totally fine

auto& c = string[0];
c = 'r'; // totally fine

为什么std::string::data()std::string::c_str()返回char* ,或者为什么std::string::operator[]返回char const&

这背后的原理是什么?

operator []使您可以直接访问std::string对象的受控序列。 c_str()最初没有。

std::string的原始规范中,不要求存储的序列是以零结尾的字符串。 这意味着在一般情况下c_str()无法返回指向存储序列的直接指针。 它必须返回一个指向完全独立的、单独分配的受控序列临时副本的指针(添加一个零终止符)。 因此,尝试修改c_str()返回的 C 字符串毫无意义。 应用于该单独 C 字符串的任何修改都不会传播到实际受控序列。 (事实上​​,规范明确禁止任何修改尝试。例如,对于一个空的std::string一个实现可以简单地返回一个指向字符串文字""的指针,这当然是不可修改的,并且可以很容易地在所有std::string对象。)因此,让c_str()返回const char *是非常有意义的。

C++11 更改了c_str()的内部规范,使其返回一个指向实际受控序列的直接指针。 但是c_str()的外部规范保持不变,以使其与旧规范保持一致。

由于历史原因,C++ 及其标准库支持 C 字符串(字符数组),并且很多 C++ 代码使用 C 字符串进行输入和输出。

您还可以想象将数据保存在字符数组中的 std::string 的可能实现。 这通常是一个完全私有的实现细节,不会通过类的公共接口公开。

编辑:明确地说,一个类通常不会公开其私有数据的非常量视图。 要了解为什么会出现此问题,请想象以下代码:

std::string s("abc");  
char* ps = s.c_str();  //  ps[0] == 'a' and ps[3] == '\0'
ps[3] = 'd';  // string is not null terminated
printf("%s", s.c_str());  // printing non-terminated string.

这种更改将允许类的用户以破坏不变量的方式更改其私有数据,即以下不变量:“用于存储的字符缓冲区将以空值结尾。”

operator[]部分约定是调用者不能提供大于或等于字符串长度的参数。 at(size_t pos)成员函数通过抛出异常来强制执行边界检查。 std::string::operator[]仍然可以不安全地使用,至少可以记录一个 contract ,这与ps[3]的指针取消引用运算符不同。

编辑结束

但是为了支持与需要const char* C 字符串的函数的互操作性, std::string公开了这个字符缓冲区。

当然,就像std::vector ,用户可能想要修改字符串中的单个元素(字符),这就是字符串提供operator[]

(实际上, string实现通常有一个固定长度的字符缓冲区,它们在内部保留,然后如果字符串的内容超过该固定长度,则在堆上“重新分配”。这称为“小字符串优化”。)

为什么会有data()成员函数,你可能会问,什么时候有一个完美可用的c_str()成员函数? 我认为这是为了简化泛型编程: std::arraystd::vector也有data()成员函数,而std::string被设计成像容器一样。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM