Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/148.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么不允许通过检索到的字符串数据指针修改字符串?_C++_String_C++11_Buffer_Language Lawyer - Fatal编程技术网

C++ 为什么不允许通过检索到的字符串数据指针修改字符串?

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必须允许实

在C++11中,
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字符
  • 返回指向静态内存的指针,其中包含NUL字符。因此,如果是空字符串,则每个
    std::string
    实现将返回相同的指针
  • 不应该强迫每个人实现SSO。因此,标准委员会需要一种方法来将#2保留在桌面上。其中一部分是从
    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:“允许”和“礼貌”之间有区别.A
    const
    对象是您与其他代码之间的契约。取消
    const
    就是违反了该契约。在某些条件下,语言可能允许这样做,但无论代码给了您什么对象,它都会告诉您不要触摸。如果有人告诉您不要坐在沙发上,而您却这样做了,则嘿,他们可能不会因为这件事把你赶出家门。但他们也不会善待你。在很多情况下,“写下就复制”也许仍然是个好主意。嵌入式系统实现可能会从识别字符串是从存储在ROM中的文本构造而来,并让字符串对象识别文本而不是为其分配堆对象中获益匪浅;复制文本在ROM中的字符串或其部分不需要分配新的堆存储e表示文本的副本。将写时拷贝应用于RAM中的内容可能过于复杂,无法证明文本的正确性,但如果实现可以使用特定于实现的……确定字符串是否存储在ROM中的方法,则将写时拷贝应用于这些情况可能比将其应用于RAM字符串更容易,但仍然提供了很多功能好处[不仅仅是速度--写时拷贝将使小型嵌入式系统能够在ROM中使用比设备的整个RAM都大的字符串!]。
    std::string stupid;
    const char *pointless = stupid.c_str();