C++ 为什么不允许通过检索到的字符串数据指针修改字符串?
在C++11中,C++ 为什么不允许通过检索到的字符串数据指针修改字符串?,c++,string,c++11,buffer,language-lawyer,C++,String,C++11,Buffer,Language Lawyer,在C++11中,std::string的字符必须连续存储,正如§21.4.1/5所指出的: 基本字符串对象中的类字符对象应连续存储。也就是说,对于任何基本字符串对象,标识&*(s.begin()+n)==&*s.begin()+n应适用于n的所有值,以便0 为什么我们不能直接写入这个缓冲区 我将陈述显而易见的一点:因为它是const。丢弃一个const值,然后修改该数据是。。。粗鲁 现在,为什么它是常量?这要追溯到写时拷贝被认为是一个好主意的时代,因此std::basic_string必须允许实
std::string
的字符必须连续存储,正如§21.4.1/5所指出的:
基本字符串对象中的类字符对象应连续存储。也就是说,对于任何基本字符串对象,标识&*(s.begin()+n)==&*s.begin()+n应适用于n的所有值,以便0
为什么我们不能直接写入这个缓冲区
我将陈述显而易见的一点:因为它是const
。丢弃一个const
值,然后修改该数据是。。。粗鲁
现在,为什么它是常量?这要追溯到写时拷贝被认为是一个好主意的时代,因此std::basic_string
必须允许实现支持它。获取一个指向字符串的不可变指针(例如,用于传递给C-API)而不产生副本开销是非常有用的。所以c_str
需要返回一个const
指针
至于为什么它仍然是常量?好。。。标准中有一个奇怪的东西:空终止符
这是合法代码:
std::string stupid;
const char *pointless = stupid.c_str();
无意义
必须是以NUL结尾的字符串。具体来说,它必须是指向NUL字符的指针。那么NUL角色是从哪里来的呢?std::string
实现有两种方法可以实现此功能:
std::string
实现都有一个内部缓冲区,它可以用于单个NUL字符std::string
实现将返回相同的指针c_str()
中给你一个const
字符串。由于这个内存很可能是真实的常量
,而不是假的“请不要修改这个内存常量
”,给你一个指向它的可变指针是个坏主意
当然,您仍然可以通过执行&str[0]
来获得这样一个指针,但是标准非常清楚这一点
话虽如此,修改&str[0]
指针及其字符数组是完全有效的。只要你保持在半开范围[0,str.size()
),你就不能通过data
或c_-str
返回的指针来完成。是的,即使标准实际上要求str.c_-str()==&str[0]
为真
这对你来说是标准的。我真的不知道,这就是为什么我这么问,但我正在点击
&text[0]
或text.begin()
不会在提供的示例案例中给出你想要的东西?(或者可能我用错了,这不会让我感到震惊=p).挑剔:一个好的C-Api也应该有长度,所以它应该是GetText(text.data(),text.size());
:P@WhozCraig,那么,第二个框中的#1应该是说操作符[]
,尽管它接受代码时看起来很糟糕,所以我现在就不说了。这应该排除&文本[0]
,但这很奇怪,因为我们可以使用操作符[]
来修改它,但不能通过等效指针来修改它。我来看看开始()
不得不说。@Nawaz,是的,我应该将其调整为长度+1
,但我决定不只是为了这个而编辑它。@Nawaz这是一个很好的观点。谢谢你的回答。在你的第一点上,这只是“粗鲁”如果它首先是常量。拥有非常量数据,返回一个指向它的常量指针,并将指针强制转换为一个你可以使用的指针是可以的,因为数据本身不是常量,这正是我所想的。但是,有可能返回预制常量内存会把这一切搞砸。我正想问是否可以让API覆盖了空终止符,但随后我看到了你的链接:p我很高兴通过&str[0]
)@chris:“允许”和“礼貌”之间有区别.Aconst
对象是您与其他代码之间的契约。取消const
就是违反了该契约。在某些条件下,语言可能允许这样做,但无论代码给了您什么对象,它都会告诉您不要触摸。如果有人告诉您不要坐在沙发上,而您却这样做了,则嘿,他们可能不会因为这件事把你赶出家门。但他们也不会善待你。在很多情况下,“写下就复制”也许仍然是个好主意。嵌入式系统实现可能会从识别字符串是从存储在ROM中的文本构造而来,并让字符串对象识别文本而不是为其分配堆对象中获益匪浅;复制文本在ROM中的字符串或其部分不需要分配新的堆存储e表示文本的副本。将写时拷贝应用于RAM中的内容可能过于复杂,无法证明文本的正确性,但如果实现可以使用特定于实现的……确定字符串是否存储在ROM中的方法,则将写时拷贝应用于这些情况可能比将其应用于RAM字符串更容易,但仍然提供了很多功能好处[不仅仅是速度--写时拷贝将使小型嵌入式系统能够在ROM中使用比设备的整个RAM都大的字符串!]。
std::string stupid;
const char *pointless = stupid.c_str();