我可以更改已分配给std::string_view的std::string吗?

5
我刚刚知道C++17引入了std::string_view。它不保存任何字符串,而是指向一个字符串。如果是这样的话,我对下面的情况感到困惑:
std::string str = "abc";
std::string_view strV = str;
std::cout << strV << std::endl;
str = "1";
std::cout << strV << std::endl;

我刚刚在一些在线的C++17编译器上尝试了这段代码,以下是输出结果:
abc
1c

显然,1c不是我预期的结果。
那么这是否意味着我们不应该更改已分配给std::string_view的字符串?

1
不清楚你期望的是什么,但从这段代码中期望任何特定的东西都是错误的,因为它的行为是未定义的。 - n. m. will see y&#39;all on Reddit
1
一种观点是,视图是对底层数据的一种展示,如果你改变了底层数据,你的视图所“看到”的内容也会发生变化。而且由于std::string可以重新分配内存,你可能会突然得到一个不再有效的内存视图。我认为关于string_view的文档在这方面非常清楚。 - Pepijn Kramer
1
一种观点是,视图是对底层数据的一种观察,如果你改变了底层数据,你的视图所“看到”的内容也会发生变化。而且由于std::string可以重新分配内存,你可能会突然间拥有一个不再有效的内存视图。我认为关于string_view的文档在这方面非常清楚。 - Pepijn Kramer
1
我建议您避免以可能导致底层字符串数据发生更改的方式使用std::string_view - Galik
1
我建议你避免以允许底层字符串数据发生变化的方式使用std::string_view - Galik
显示剩余3条评论
3个回答

7
一般来说,你不应该这样做,因为它很脆弱。
无论如何:

你可以改变引用后面的数据(std::string_view是对字符串段的引用,而不是对字符串的引用,由起始位置和长度组成),只要意识到你已经这样做了以及如何做到的。
但是,避免释放它,使用悬空引用是不好的。

std::string如果新值适合当前容量且没有移动赋值,或者两者都处于SBO模式,则不会重新分配内存。
在你的例子中,这三个条件都成立。

唯一的问题是,在赋值之后,字符串终止符后面的数据是不确定的,尽管它没有被明确覆盖,为了效率仍然保持为c


1
是的,基本上我唯一会考虑接受的更改就是类似于str[1] = '1'这样的原地更改。赋予新值则肯定是由具体实现确定的,所以我不会依赖它。 - maxbachmann
1
基本上,我只会考虑一些原地修改的变化,比如 str[1] = '1'。给变量赋予新值肯定是由具体实现定义的,所以我不会依赖这种方式。 - maxbachmann
1
@MatteoItalia 将该警告更加突出。 - Deduplicator
1
@MatteoItalia 把那个警告更加突出。 - Deduplicator
1
@MatteoItalia 把那个警告更加突出。 - undefined
显示剩余2条评论

6

string_view存储了字符串的起始指针和字符串的长度。 替换string_view中存储的文本会导致两者都无效,因为这可能导致不同的长度和/或不同的存储位置。

所以是的,改变字符串会使string_view无效。


但是字符串没有被替换,只是其值改变了。在这种情况下,细节很重要。 - Deduplicator
但是字符串并没有被替换,只有它的值被改变了。在这种情况下,细节很重要。 - Deduplicator
1
是的,这个有点不清楚。我确实指的是存储的字符串值。所以基本上,一旦你给一个新的字符串赋值,你就使这个字符串无效了(除非有SSO,但你真的不应该依赖它)。 - maxbachmann
1
是的,这个有点不清楚。我指的是存储的字符串值。所以基本上,一旦你给一个新的字符串赋值,你就使得原来的字符串无效了(除非有SSO,但你真的不应该依赖它)。 - maxbachmann
1
是的,这个有点不清楚。我是指存储的字符串值。所以基本上,一旦你给一个新的字符串赋值,你就使这个字符串无效了(除非有SSO,但你真的不应该依赖它)。 - undefined

3

std::string_view只是const引用的一种高级形式,用于存储包含字符的缓冲区。这个缓冲区可以由std::string管理,也可以是字符串字面值或一些char数组。

因此,使用std::string_view不能超出该缓冲区的生命周期。在您的示例中,在使用字符串视图之前修改了缓冲区,导致未定义的行为。

现在,由于大多数编译器都实现了小字符串优化,您的示例没有崩溃。在更一般的情况下,这段代码将失败。

请注意,std::string_view主要用于更有效地解析长字符串中的某些数据,而这些数据不会被修改。


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