为什么不能把string_view作为条件表达式?
在C++中,指针和 optional 都可以用作if语句的条件表达式:
auto *ptr = get_ptr();
if (ptr) { std::cout << "Yay, can use ptr!\n"; }
else { std::cout << "Can't use ptr, too bad..."\n; }
std::optional<sd::complex> thing = maybe_get_something();
if (thing) { std::cout << "Yay, got something!\n"; }
else { std::cout << "Nothing returned..."\n; }
但——我们不能对 std::string_view 这样做。为什么?毕竟,当它的 data 指针是 nullptr 时,它确实存在一个接近空值的状态,在指向零长度字符串的对象中,这是独特的。
解决方案
用 std::string_view 来检测“接近空值”的状态的问题在于,这种状态本质上只是错觉。是的,与 std::optional 有一个对照,因为一个默认构造的 string_view 没有数据。然而,这并不是获得空数据指针的唯一方式。一个 string_view 可能是由有效数据构造的——因此在这个意义上不应被视为“接近空值”,但它却可能拥有一个空数据指针。因此,除非在特殊情况下,一般不应把数据指针为null的视图与其他零长度视图区别对待。
正如在 另一个问题 中所解答的那样,只要大小为零,就可以从一个空指针构造一个 string_view,这是有意结果的 LWG issue 3111 的一个结果,该问题旨在使 string_view “能够与其他容器互操作”。一个与此互操作性相关的示例涉及 std::vector,并给出一个不应被视为“接近空值状态”的 string_view,但它可能具有空数据指针。
考虑将一个 vector<char> 转换为一个 string_view 的情形,这在字符数据以向量形式获取、但被当作字符串查看时,是合理的。转换函数相当直接。
#include <string_view>
#include <vector>
std::string_view as_string_view(const std::vector<char>& data) {
return {data.data(), data.size()};
}
由于结果是由实际数据构造的,因此在没有值的意义上,它不会是一个 optional 的“空值”。然而,如果 vector 为空,结果将是一个零长度的 string_view。此外,如果 vector 为空,它的 data() 成员可能返回也可能不返回空指针。也就是说,如果 vector 为空,得到的 string_view 可能与默认构造的 string_view 无法区分。也许也不是。标准允许两种可能性。基于 data() 是否为空来区分 string_view,将是一个错误。
为了演示,请尝试使用上述函数的以下代码。
#include <iostream>
void report(std::string_view view) {
// Output the pointer value.
std::cout << static_cast<const void*>(view.data()) << '\n';
}
int main() {
std::vector<char> data;
report(as_string_view(data));
data.push_back('a');
report(as_string_view(data));
data.pop_back();
report(as_string_view(data));
data.shrink_to_fit();
report(as_string_view(data));
}
结果没有任何保证,但在我的尝试中(使用GCC 13),第一种和最后一种转换产生了一个带有空数据指针的 string_view,而另外两种产生了非空数据。值得注意的是,最后一次转换的差异在于对 shrink_to_fit 的调用,它是出于内存优化的目的,而非数据操作。我认为这表明“接近空值”的概念对 string_view 并非有用。相反,通常有用的测试是 empty()(必须在条件中显式调用,方式与 std::string 的工作方式相似)。
0
0x1aea52c0
0x1aea52c0
0