C++11 为什么';t string::data()是否提供可变字符*?

C++11 为什么';t string::data()是否提供可变字符*?,c++11,c++,string,containers,c-strings,c++17,C++11,C++,String,Containers,C Strings,C++17,在数组中,字符串和向量都得到了数据方法,该方法: 返回指向用作元素存储的基础数组的指针。指针使范围[data();data()+size())始终为有效范围,即使容器为空。 [] 此方法在所有适用容器的可变和const版本中提供,例如: T* vector<T>::data(); const T* vector<T>::data() const; 这里发生了什么?当char*string::data()会很有帮助时,为什么string会被短改?我认为这一限制来自于(20

数组
中,
字符串
向量
都得到了
数据
方法,该方法:

返回指向用作元素存储的基础数组的指针。指针使范围[
data()
data()+size()
)始终为有效范围,即使容器为空。 []

此方法在所有适用容器的可变和
const
版本中提供,例如:

T* vector<T>::data();
const T* vector<T>::data() const;

这里发生了什么?当
char*string::data()
会很有帮助时,为什么
string
会被短改?

我认为这一限制来自于(2011年之前)的时代,
std::basic_string
不必将其内部缓冲区存储为连续字节数组

而所有其他(
std::vector
等)必须按照2003年的标准将其元素存储为连续序列;因此
数据
可以轻松返回可变
T*
,因为迭代等没有问题

如果
std::basic_string
返回一个可变的
char*
,这意味着您可以将该
char*
视为有效的C字符串,并执行类似于
strcpy
的C字符串操作,如果字符串没有连续分配,则很容易转向未定义的行为

C++11标准增加了
basic_string
必须作为连续字节数组实现的规则。不用说,您可以使用
&str[0]的老技巧来解决这个问题

简单的回答是,它确实提供了。这对于类似的情况非常重要,因此,要获得对底层C字符串的可变访问权,我现在可以执行以下操作:

auto foo = "lorem ipsum"s;

for(auto i = data(foo); *i != '\0'; ++i) ++(*i);

出于历史目的,值得记录
string
的发展,其基础是:在访问
string
的过程中,一个新的要求使得底层缓冲区成为可能,即它的元素被连续存储,以便对于任何给定的
string s

&*(s.begin()+n)==&*s.begin()+n
对于[
0
s.size()
)中的任何
n
,或者,可以将指向
s[0]
的指针传递给需要指向
图表[
数组的第一个元素的函数

可以通过各种方法获得对这个新要求的底层C字符串的可变访问,例如:
&s.front()
&s[0]
,或
&s.first()
但回到原来的问题,这将避免使用其中一个选项的负担:为什么没有以
char*string::data()的形式提供对
string
的底层缓冲区的访问?

要回答这个问题,需要注意
T*数组::数据()
T*向量::数据()
是的一个附加要求。对于其他连续容器,如
deque
,没有产生任何附加要求。当然,对于
字符串
,也没有附加要求,事实上,该要求是新的。在此之前,该要求已经存在。尽管它明确地不能保证指向对于任何底层缓冲区,这是从
字符串
获取
常量字符*
的唯一方法:

返回的数组不需要以null结尾


这意味着
string
没有被“短改”在向
数据
访问器的转换过程中,它根本不包括在内,因此只有
常量
数据
访问或
字符串
之前拥有的访问被保留下来。有一些需要直接写入
字符串
的底层缓冲区的内容,我们已经讨论过了,并将其记录为一个问题它是:
&s[0]
,用于非空字符串。我认为,如果您需要通过
数据
修改字符串,您可能正在寻找
向量
。但也有一些例外情况。@black我广泛使用
向量
,每次都很遗憾,后来我将字符复制回
字符串
。什么实际上我想要的是一个带有可修改缓冲区的
字符串
方法将通过鼓励开发人员将
string
对象用作字节缓冲区来击败它的封装。因此,这将是一个倒退的步骤。根据这里的说法:
std::string::data
自C++98以来就已经存在。它还谈到了我在这里提出的相同问题。@JonathanMee我肯定有在很多情况下,我确信这是一件好事:-)我想至少方法
data()
明确表达了意图,而
&s[0]
是神秘的。所以,好吧,我被说服了。@JonathanMee如果因为缺少合适的操纵器而缺少ostream功能,那么修复标准使其提供一个不是更好吗?在我看来,将格式化数据发送到流中可以通过一种更为封装的方式来实现,而不是求助于
sprintf
在主线代码中。作为自定义实用程序函数的一个实现细节,它更容易被原谅,IMHO。@JonathanMee总的来说,我同意你的看法。提供一个可变的
数据()
比用
&s[0]
addressof(*begin(s))破解它要不那么神秘
。我想我们刚刚创造了历史。我刚刚在互联网上公开改变了我的观点:-)
auto foo = "lorem ipsum"s;

for(auto i = data(foo); *i != '\0'; ++i) ++(*i);