C++字符串是否可变,与Java字符串不同?

43

在C++中这样操作字符串可以吗:

string s = "Sting";
s[2] = 'a';

它运行得很好(并打印出 'String'),但这样做是否安全?

如果是,这是否意味着它们是可变的?


15
是的,std::string是可变的。然而,字符串字面值是不可变的。 - T.C.
1
那很可能是C++字符串。但你应该澄清你的意思是什么。 - juanchopanza
1
注意:在C++中,char* s = "content"已经被弃用,应该使用不可变的const char* s = "content"。假设你的示例字符串是一个std::string,那么std::string和字符数组s[] = "content"(与上面的char*/const char*不同)是可变的。 - user2249683
@AnonymousAndy: "String"是一个字符串字面值。它的值用来初始化s,它是类型为std::string的一个对象,而不是一个字符串字面值。字符串字面量是不可变的;s则不是。 - Keith Thompson
1
不。上面的例子在堆栈上创建了一个字符串对象,并用"Sting"初始化了它所拥有的内存。C++和Java完全不同。请找一本好的C++书籍并阅读它。你会为此感到高兴的。 - Rob K
显示剩余4条评论
7个回答

28

C++字符串字面值,例如"literal",是不可变的,尽管C++03允许将指针分配给这样的字面值char*(这个特权在C++11中被弃用和删除)。试图更改字符串字面值的字符是未定义的行为:

char* s = "literal"; // OK with C++03; illegal with C++11 and later
s[0] = 'x';          // undefined behavior

C++中的std::string对象如果没有声明为std::string const,则可以被修改。如果您认为char对象序列相互独立,则可以将值分配给单个对象。然而,通常字符串实际上包含以UTF-8字节编码的Unicode。如果是这种情况,更改字符串中任何元素可能会破坏正确的编码,例如因为连续字节被替换为其他内容。

因此,是的,这些字符串是可变的,但从语义角度考虑,逐个分配值可能不安全。


19

字符串字面量本身与 Java 中一样是不可变的。

字符串字面量存储在只读内存部分中。

例如,如果您执行以下操作,将会得到一个 segfault(段错误):

char *ptr = (char *) "hello";
ptr[0] = 'a';  //segfault! you can't change something that's immutable

然而!你可以使用s[2] = 'a'来修改字符串,除非该字符串用const关键字声明。

原因是字符串的=运算符是重载的,它以字符串字面量为参数,然后循环遍历字符串字面量并将每个字符复制到可变的char数组中。

因此,如果你在Java和C/C++中比较字符串字面量,它们在不可变性方面具有相同的行为。C++字符串类的实例是可变的,但Java String类的实例是不可变的。

以下是一个示例,显示该字符串具有副本:

#include <iostream>
#include <string>

using namespace std;

int main()
{
  const char *ptr = "hello";
  string s = ptr;

  s[0] = 'b';

  cout << s << endl; //prints bello
  cout << ptr << endl; //prints hello

  return 0;
}

1
请解释一下您所说的字符串字面值不是不可变的意思。我的意思是,字符串字面值中用双引号括起来的任何内容,对吗?而且在我提供的示例中,我们确实改变了它。请解释一下,兄弟。 - abcde
1
是的,双引号中的任何内容都是字符串字面量。该字符串存储在只读内存部分中。因此,它是不可变的,因为您无法写入此内存。在您提供的示例中,您没有改变字符串字面量。您改变了存储在String对象中的副本。我将打出一个示例,使这个概念非常清晰。 - Kacy
4
在你的例子中,第一行将字符串字面值取出,并创建一个std::string对象。这在概念上与你做int a = 1;没有任何区别。你可以改变a的值,对吧?但你不能改变1 - PaulMcKenzie

4
C++中的std::string是可变的,而赋值(通常)会复制字符串数据。Java中的String是不可变的,赋值会复制对字符串的引用。
类型std::shared_ptr< const std::string >在某种程度上类似于Java字符串。然而,它只是C++中的一个贫民版替代品。在C++03中,它对优化例如排序字符串集合等方面有一定意义,但随着C++11移动语义的出现,它已经不再对任何事情产生影响了——除了学术观点外。

3

是的,没错。

这就像在位置2修改一个数组。


3

没错,它是完全安全的,是可变字符串,这意味着您可以更改它们,附加新内容并从中删除部分。


1
在C++中,字符串是可变的,但随着强大的功能而来的是巨大的责任:如果您从或存储到超出字符串内存范围的位置,您将会得到未定义的行为。例如,在您的示例中,如果引用了s[12],您将会得到未定义的行为。

-1

字符串 C++ 可变的。(字符串数据被复制) Python 不可变的。(字符串引用被复制) Java 不可变的。(字符串引用被复制)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接