看一下这个例子(取自here):
class foo {
std::string my_str_;
public:
std::string_view get_str() const {
return my_str_.substr(1u);
}
};
此代码很糟糕,因为substr
返回临时std::string
,因此返回的std::string_view
引用已经被破坏的对象。但是,如果substr
返回std::string_view
,则此问题将不存在。
此外,如果substr
返回std::string_view
而不是std::string
,似乎合乎逻辑,因为返回的字符串是字符串的视图,而且性能更高,因为没有副本是的。
如果substr
返回std::string_view
会有任何缺点(除了明显的缺点:失去与C ++ 14的兼容性 - 我没有低估这一点的重要性,我只是喜欢知道是否存在其他缺点)?
相关问题:How to efficiently get a `string_view` for a substring of `std::string`
答案 0 :(得分:2)
当string_view
被发明时,关于它是否应该存在的争论太多了。所有相反的论点都来自你所展示的例子。
然而,就像我总是告诉每个人这样糟糕的例子:C ++不是Java,也不是Python。 C ++是一种低级语言,你对几乎完全控制超过内存,我重复蜘蛛侠的陈词滥调:强大的力量带来了巨大的责任。如果你不知道string_view
是什么,那么就不要使用它!
你问题的另一部分有一个简单的答案,你自己回答:
如果substr返回std :: string_view会有任何缺点(除了明显的缺点:与C ++ 14失去一些兼容性)?
使用来自substr
的字符串副本的每个程序都可能不再有效。向后兼容性在计算机业务中是一件严肃的事情,这就是为什么英特尔的64位处理器仍然接受x86指令,这也是他们没有停业的原因。重新发明轮子要花很多钱,金钱是编程的重要组成部分。所以,除非你打算把所有的C ++都扔进垃圾箱并重新开始(比如RUST),你应该在每个新版本中维护旧的规则。
你可以弃用东西,但要非常小心和非常慢。但是,弃用与改变API不同,这就是你的建议。
答案 1 :(得分:1)
缺点很明显:与每个版本的C ++重新开始相比,这将是一次重大的API破坏变化。
C ++不是一种容易破坏API兼容性的语言。
答案 2 :(得分:1)
这是一个当前安全的代码的具体(如果稍微不完整)示例,但随着更改将成为未定义的行为:
std::string some_fn();
auto my_substr = some_fn().substr(3, 4);
可以说auto
的使用在这里有点可疑,但在以下情况下(在我看来)完全合理,重复类型名称几乎是多余的:
const char* some_fn();
auto my_substr = std::string(some_fn()).substr(3, 4);
编辑:即使substr()
总是返回std::string_view
,您也可以想象这段代码会造成一些痛苦,即使只是在开发/调试过程中。
答案 3 :(得分:0)
首先,c ++字符串的基础数据结构主要与c字符串保持兼容(可通过c_str()
成员访问)。 C字符串null
终止。所以你基本上只有一个起始char
指针,并保持增量,直到指针指向0
。
因此子字符串可以从原始字符串的任意位置开始。但是,由于您不能在原始字符串中的某处插入null
,因此您的子字符串仍然需要与原始字符串在同一位置结束。
- edit--
正如John Zwinck所指出的,c ++字符串可以包含\0
个字符,但是这仍然意味着子字符串会松散它们的c_str
成员,因为它需要修改原始字符串。在Using std::string_view with api, what expects null terminated string
string_view
的缺点