【问题标题】:Is it valid to pass nullptr to std::string::assign?将 nullptr 传递给 std::string::assign 是否有效?
【发布时间】:2021-10-27 20:59:44
【问题描述】:

我有一个返回指针和长度的函数,我想调用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,但这几乎不能保证。

【问题讨论】:

  • 在相关说明中,char a[4]; s.assign(s+4, 0); 是否合法?这似乎是对“长度为 0 的数组”的合理解释,并且在实践中可能会出现。

标签: c++ language-lawyer c++-standard-library


【解决方案1】:

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

另一方面,如果n 为零,则不允许实现取消引用指针,因为指针可能指向大小为零的数组,并且取消引用这样的指针将具有未定义的行为。此外,没有任何必要这样做,因为没有任何内容被复制。

上述推理并不意味着忽略UB就可以了。但是,如果没有理由禁止s.assign(nullptr, 0),那么最好将标准的措辞更改为“如果 n 大于零,则 s 指向...”。我不知道有什么好的理由拒绝它,但我也不能保证不存在一个好的理由。

请注意,添加检查并不复杂:

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

什么是零字符数组

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

【讨论】:

  • 允许实现检查指针的有效性。检查指针是否指向分配的内存,甚至简单检查__debug_assert(cstr != nullptr) 可以存在于任何符合要求的实现中
  • @Revolver_Ocelot 可以,正如我所说,标准不保证行为。我希望任何检查指针的实现,只有在指针被取消引用时才会这样做。
  • 如果我必须为零长度做一个特殊情况,我更喜欢打电话给clear()
  • 实际上,如果长度为零,则我传递给assign 的指针不是显式的nullptr 文字,而是一个诚实的char*,可能恰好为NULL。
  • @Bulletmagnet ,好吧,libc++ 和 libstdc++ 都做类似assert(len == 0 || ptr != nullptr) 的事情,所以至少可以安全地使用这些库。不要左右VS。如果代码中存在空指针滑动的危险,使用建议的三元运算符方法会更安全。
【解决方案2】:

正如您所指出的,标准说“s 指向一个数组...”。空指针不指向包含任意数量元素的数组。甚至没有 0 个元素。另外,请注意s 指向“一个至少 n 元素的数组...”。所以很明显,如果n 为零,你仍然可以将合法的指针传递给数组。

总的来说,std::string 的 API 没有很好地防范指向 charT 的空指针。所以你应该始终确保你传递给它的指针是非空的。

【讨论】:

    【解决方案3】:

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

    也就是说,我宁愿谨慎行事。您可以争辩说您不符合标准要求:

    21.4.6.3 basic_string::assign

    8要求:s指向一个至少有n个charT元素的数组

    因为nullptr 没有指向一个数组

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

    【讨论】:

      【解决方案4】:

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

      指针字面量是关键字 nullptr。它是std::nullptr_t 类型的纯右值。 [ 注意:std::nullptr_t 是一个独特的类型,既不是指针类型也不是指向成员类型的指针 ... ]

      std::nullptr_t 可以根据 4.10.1 [conv.ptr] 隐式转换为任何类型的空指针。不管空指针的类型如何,事实仍然是它指向 nothing

      因此,它不满足s指向一个至少有n个charT元素的数组的要求

      这似乎是未定义的行为。

      有趣的是,根据this answer,C++11 标准明确规定sbasic_string 构造函数中不得为空指针,但此后该措辞已被删除。

      【讨论】:

      • True 但 nullptr_t 可以隐式转换为任何类型的空指针,包括 char*。问题是生成的空指针没有指向任何东西,甚至没有 0 个字符,但类型不是问题。
      • @rici 谢谢。我编辑了我的帖子,但担心它与其他提供的答案非常相似。
      猜你喜欢
      • 2012-06-02
      • 2021-11-07
      • 2015-09-26
      • 2021-12-10
      • 2013-09-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多