关于std::string_view{nullptr,0}的合法性、相关C++标准条款及P2166提案的技术问询
std::string_view{nullptr, 0}的合法性、相关C++标准条款及P2166提案的技术问询 咱们一步步拆解你的问题,从核心的合法性说起,再延伸到提案细节和你的疑问:
1. 核心问题:std::string_view{nullptr, 0}是否良定义?
先看你的测试代码:
#include <string_view> int main() { auto _ = std::string_view{ nullptr, 0 }; }
结论是:这是完全符合C++标准的良定义代码。
根据[string.view.cons]中std::basic_string_view带指针和大小的构造函数的前置条件:
Preconditions : [str, str + len) is a valid range.
C++标准里对“有效范围”的定义中,空范围(起始和结束指针/迭代器相等)是天然有效的——哪怕起始指针是nullptr。因为空范围不需要访问任何内存,前置条件只要求范围本身有效,而空范围的有效性不依赖指针指向可访问内存(只有非空范围才要求指针指向可访问的连续内存)。nullptr + 0还是nullptr,所以[nullptr, nullptr)是合法的空范围,完全满足前置条件。
2. P2166提案的“Further Discourse”部分解析
提案作者的逻辑是:既然带指针和大小的构造函数要求[s, s+count)是有效范围,那如果传入nullptr作为指针,只要count不是0,行为就是未定义的。那干脆把basic_string(nullptr_t, size_t)和constexpr basic_string_view(nullptr_t, size_t)都删掉?
但这部分没放进主提案,原因是:这会破坏**合法但不合理(not legitimate)**的现有代码——比如std::string{nullptr, 0}和std::string_view{nullptr, 0}这种写法。
关于你问的细节:
- “citation source is the same”的参考:指的就是[string.view.cons](对于string_view)和[string.cons](对于std::string)中,带指针和大小的构造函数的相同前置条件条款,也就是要求
[s, s+count)是有效范围的那部分内容。 - “legal, yet not legitimate”的含义:
Legal:完全符合当前C++标准的规则,是良定义的,编译器不会报错,行为符合标准要求。Not legitimate:这种写法没有实际必要、容易误导阅读者、且存在潜在误用风险。比如:- 效果上,
std::string_view{nullptr, 0}和默认构造的std::string_view{}完全等价,都是空视图。 - 写法上会让维护代码的人困惑:为什么要传nullptr和0?是不是原本想传一个非空指针但写错了?
- 风险上,如果有人不小心把
0改成了非0值,立刻就会触发未定义行为(因为[nullptr, nullptr+N)是无效范围,N>0时)。
- 效果上,
所以虽然它符合标准,但不是一种合理、推荐的代码写法,也就是“not legitimate”。
3. 你的实际使用场景解析
你提到的实际业务代码:
#include <string_view> struct X { operator char const*() const { return nullptr; } private: friend size_t len(X const&) { return 0; } }; int main() { X const x{}; auto _ = std::string_view{ x, len(x) }; }
这种场景下,构造是合法的,因为最终还是等价于std::string_view{nullptr, 0}。不过从代码可读性和可维护性角度,更推荐直接返回std::string_view{},这样能避免让其他开发者疑惑为什么会有nullptr参与构造,也能消除潜在的误用风险。
内容来源于stack exchange

