问题
-
有的大佬建议使用
std::string_view
替代const std::string&
,也有的大佬表示反对,到底该不该呢? -
以下代码运行后显示什么?
1 |
|
分析
反对者可能是 C 语言的受害者!(这里没说反对得不对哦!)
先看看 CppCoreGuidelines 的说法:
In C++17, we might use string_view as the argument, rather than const string& to allow more flexibility to callers
这里说的是使用 std::string_view
作为参数,能够适配更多的调用者。不管传入 const char*
类型,还是 std::string
类型的变量,都能编译。
反之,如果参数是 const std::string&
类型,则有以下缺点:
-
传入
std::string_view
类型无法编译。 -
传入
const char*
类型,会多构造一个std::string
类型的临时变量。
但是 CppCoreGuidelines 并没有建议把 const std::string&
参数都替换成 std::string_view
,而是说字符串是一个大话题,需要分很多种情况讨论。具体可见 SL.str: String
节,下面列出大概意思:
Text manipulation is a huge topic.
std::string
doesn’t cover all of it.
This section primarily tries to clarifystd::string
’s relation tochar*
,zstring
,string_view
, andgsl::span<char>
.
The important issue of non-ASCII character sets and encodings (e.g.,wchar_t
, Unicode, and UTF-8) will be covered elsewhere.
- SL.str.1: Use
std::string
to own character sequences- SL.str.2: Use
std::string_view
orgsl::span<char>
to refer to character sequences- SL.str.3: Use
zstring
orczstring
to refer to a C-style, zero-terminated, sequence of characters- SL.str.4: Use
char*
to refer to a single character- SL.str.5: Use
std::byte
to refer to byte values that do not necessarily represent characters- SL.str.10: Use
std::string
when you need to perform locale-sensitive string operations- SL.str.11: Use
gsl::span<char>
rather thanstd::string_view
when you need to mutate a string- SL.str.12: Use the
s
suffix for string literals meant to be standard-librarystring
s
那么,究竟啥场景能用 std::string_view
类型参数?
F.25: Use a zstring
or a not_null<zstring>
to designate a C-style string 节有一句话:
If you don’t need null termination, use
string_view
.
这句是重点!因为 std::string_view
并不保证 Null-terminated,如果函数使用 std::string_view
参数,却做了 Null-terminated 的假定,那么,在把参数传给其它 C-Style API 时,就可能导致 bug,甚至崩溃。
例如,这位大佬的文章说的情况:
- The Case of string_view and the Magic String
- Why Don’t You Use String Views (as std::wstring_view) Instead of Passing std::wstring by const&?
简单地说,std::string
是保证 Null-terminated 的,而 std::string_view
不保证,当 const std::string&
参数被替换为 std::string_view
时,对于部分没有 Null-terminated 的字符序列,C-Style API 可能读入超过范围的字符,而导致逻辑上的错误,还可能因为读到无权限的地址而崩溃。
总结
简单地说,看情况而定。总之,为了写高质量的 C++ 代码,必须细分这么多的情况。
但您如果熟悉 C 语言,可能会提出疑问:大部分 CRT 函数或 C-Style API 不都做了字符串是 Null-terminated 的假定?确实如此!如果人人写好注释,人人遵守规则,那确实能把代码简化。问题是:异常和意外,哪个先来?