将 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标准明确规定s
在basic_string
构造函数中不能是空指针,但是这个写法后来被已删除。
我有一个 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]:
根据 4.10.1 [conv.ptr],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 ... ]
std::nullptr_t
可以隐式转换为任何类型的空指针。无论空指针的类型如何,事实仍然是它指向 nothing.
因此,不满足s指向charT.
至少有n个元素的数组的要求这似乎是未定义的行为。
有趣的是,根据this answer,C++11标准明确规定s
在basic_string
构造函数中不能是空指针,但是这个写法后来被已删除。