将 nullptr 传递给 std::string::assign 是否有效?

Is it valid to pass nullptr to std::string::assign?

我有一个 returns 指针和长度的函数,我想调用 std::string::assign(pointer, length)。当长度为零且指针可能为 nullptr 时,我是否必须做一个特殊情况(调用 clear)?

C++ 标准说:

21.4.6.3 basic_string::assign

basic_string& assign(const charT* s, size_type n);
Requires: s points to an array of at least n elements of charT.

那么如果 n 为零呢?什么是零字符数组,一个字符如何指向它? 调用有效吗

s.assign(nullptr, 0);

还是未定义的行为?

当大小 n 为零时,libstdc++ 的实现似乎不会取消引用指针 s,但这很难保证。

正如您指出的那样,标准说“s 指向一个数组...”。空指针不指向任何数量元素的数组。甚至没有 0 个元素。另外,请注意 s 指向 "an array of at least n elements..."。所以很明显,如果 n 为零,您仍然可以将合法的指针传递给数组。

总的来说,std::string 的 API 不是 well-guarded 针对 charT 的空指针。所以你应该始终确保你传递给它的指针是 non-null.

我不确定为什么实现会取消引用任何指向长度为零的数组的指针。

话虽如此,我宁愿谨慎行事。您可以争辩说您不符合标准要求:

21.4.6.3 basic_string::assign

8 Requires: s points to an array of at least n elements of charT

因为 nullptr 没有指向 数组

所以从技术上讲,行为是未定义的。

迂腐地,nullptr 不满足指向大小为 >=0 的数组的要求,因此标准不保证行为(它是 UB)。

另一方面,如果 n 为零,则不允许实现取消引用指针,因为指针可能指向大小为零的数组,并且取消引用这样的指针将是未定义的行为。而且,也没有必要这样做,因为什么都没有被复制。

以上推理并不意味着可以忽略UB。但是,如果没有理由禁止 s.assign(nullptr, 0),那么最好将标准的措辞更改为 "If n is greater than zero, then s points to ..."。我不知道有什么充分的理由禁止它,但我也不能保证不存在一个充分的理由。

请注意,添加支票并不复杂:

s.assign(ptr ? ptr : "", n);

What is an array of zero characters

这是:new char[0]。自动或静态存储数组的大小不能为零。

来自标准 (2.14.7) [lex.nullptr]:

The pointer literal is the keyword nullptr. It is a prvalue of type std::nullptr_t. [ Note: std::nullptr_t is a distinct type that is neither a pointer type nor a pointer to member type ... ]

根据 4.10.1 [conv.ptr],

std::nullptr_t 可以隐式转换为任何类型的空指针。无论空指针的类型如何,事实仍然是它指向 nothing.

因此,不满足s指向charT.

至少有n个元素的数组的要求

这似乎是未定义的行为。

有趣的是,根据this answer,C++11标准明确规定sbasic_string构造函数中不能是空指针,但是这个写法后来被已删除。