【问题标题】:Why an empty() std::basic_string c_str() is not nullptr?为什么 empty() std::basic_string c_str() 不是 nullptr?
【发布时间】:2014-01-05 19:24:42
【问题描述】:

(周日晚上思考)

在我编写的函数中,我倾向于同时依赖 const char* 和同一字符串的模板内联 const std::basic_string<>& 变体。但我真的很好奇为什么空字符串的c_str() 不是nullptr

大多数 C++ 编码人员现在将 const char* 指针视为 C 代码,但我认为它非常 C++,因为字符串是 null 终止和连续的,并将继续以这种方式。但是如果您使用自定义分配器,那么您使用const std::string& 参数编写的所有代码都是毫无意义的(除非只有标题)

因此,您真正的选择(如果您想多才多艺) 是老式字符指针或内联模板函数,它们可以支持各种 std::basic_string 和自定义分配器或特征。这会迫使您内联模板化函数,因为您无法预先正确预测模板参数。

现在我的问题是为什么空字符串不为 c_str() 返回 nullptr? 作为字符串函数中的最低公分母,尤其是对于只读访问是const char* 而不是const std::string&,它是模板化的,因此受到限制。返回指向任何东西的指针,尤其是在没有进行字符串分配的情况下……在我看来很奇怪。

还是我太疯狂了以至于不能这样做?总是担心const char* 和模板化的const std::basic_string<char, ..., ...>& 对应物。如果std::string().c_str() where nullptr,我不会担心。但我必须自己防范空字符串,因为c_str()std::basic_strings 上不可靠。

PS:我知道旧式字符串函数在与空指针一起使用时会崩溃,但在任何地方使用字符串之前,可以轻松测试有效指针和非空第一个字符.

PPS:我在这里谈论的是健全的以 null 结尾的字符串,而不是 std::basic_string 特别支持的包含 null 的伪字符串。

问题改写:为什么std::string().c_str() 不应该指向内存?应该是nullptr。与 std::string().c_str("") 不同,后者是一个空字符串,需要一个 \0 尾随它。所以它实际上指向有效内存。 (如果您不了解字符串/指针的工作原理,请不要费心回答。这需要一些类似 C 的理解。)

【问题讨论】:

  • 空字符串是没有元素的字符串。空指针不是字符串。
  • 反对者请解释一下。
  • @Praetorian:这听起来更像是对 OP 问题的回答,而不是投反对票的理由。
  • @Benjamin :) 当我输入评论时似乎不是这样。无论如何,下面的答案更能说明为什么 c_str() 返回 nullptr 以指示空字符串是完全错误的。
  • "但是如果您使用自定义分配器,那么您使用 const std::string& 参数编写的所有代码都是毫无意义的(除非只有标头)。"这是string_view 的主要动机之一,以提供更好的const string&,它独立于内存分配细节。

标签: c++ string c++11 stl std


【解决方案1】:

std::string 的默认 constructor 将构造一个空字符串。

如果没有相应的有效 C 字符串,则无法构造 std::string 对象。 std::string() 等价于std::string(""),因此std::string::c_str() 将始终返回一个有效指针,并且从不返回一个空指针。

【讨论】:

  • 我只是在输入一条评论告诉你这样做(发表你的评论作为答案)。我喜欢空的和未明确分配的缓冲区(如字符串)null。这可能只是个人喜好......
  • 大小为 3 的 std::string(3, '\0') 怎么样!?
  • @DieterLücking 已初始化。简单的。 --- 我在我的问题中说,我非常不喜欢将空值放入 std 字符串的可能性。
【解决方案2】:

在下面的表达式中:

const char* foo = "";

有一个空字符串but I do not see a null pointer。一个空的 C 字符串是 char []char[0] = '\0',仅此而已。

const char* 类型的空指针是不存在的字符串。

【讨论】:

  • 其实这个解释很好——“空”字符串存储信息,而空指针不包含任何信息(除了为空)!
  • @DieterLücking 它的作用是有一个真实的内存地址分配给foo。如果他怀疑,请避免 OP 只相信我的话。
【解决方案3】:

如果一个空字符串的c_str返回nullptr,那么这将是无效的:

const char* str1 = "";
std::string str2 = "";
const char* str2_c = str2.c_str();
assert(strcmp(str1, str2_c) == 0);

对我来说,这似乎是一个有缺陷的界面。两个空字符串应该比较相等。

【讨论】:

  • 你混淆比澄清任何事情都多
  • empty() 与空字符串有什么关系? 空 std::string 我的意思是未分配(未分配)。 "" 字符串表示 \0,而空字符串表示未分配内存。所以空指针是有意义的。
  • @CodeAngry: std::string 没有对应于“未分配”的状态。空字符串并不意味着“没有分配内存”,无论是引用 c 字符串还是 c++ 字符串。
  • @BenjaminLindley 它应该有,因为我没有分配任何东西。对于那些理解指针的人来说,这就是 nullptr 的值。它意味着 NOTHING,而不是像 "" 中的 EMPTY。
  • @CodeAngry:不,不应该。指针是一种非常原始的类型,它可能指向也可能不指向字符串。 std::string 不是,也不应该等同于指针。 std::string 是一个字符串。它应该始终是一个字符串。如果你想要一个可以为空的类型,那么使用设计为可以为空的类型(即boost::optional<std::string>),而不是设计为字符串的类型。
【解决方案4】:

考虑一个 C 类型字符串(NULL 终止字符串)

const char * str1 = "";
const char * str2 = nullptr;
  • 第一个实现是一个大小为 0 的以 NULL 结尾的字符数组。
  • Second 只是一个初始化为 NULL 的字符指针。

如果std::string().c_str() 返回nullptr,那将是完全错误的,因为它是一个模板 C++ 字符串,相当于一个 NULL 终止的 0 大小的 C 字符串。

【讨论】:

  • 第一个指向内存,第二个指向无处。巨大的差异。
  • @CodeAngry:是的。特别是,第一个指向 C 字符串,第二个不指向,std::string::c_str() 始终返回指向 C 字符串的指针。这就是为什么它被命名为c_str。显然 c_str 不能返回 nullptr 因为那不是 C 字符串。
猜你喜欢
  • 1970-01-01
  • 2021-04-07
  • 2017-08-09
  • 1970-01-01
  • 2013-05-13
  • 2011-05-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多