std::string
提供const char* c_str ( ) const,其中:
获取等效的C字符串
生成以null结尾的序列 字符(c-string)与之相同 content作为字符串对象和 将其作为指向数组的指针返回 字符。
终止空字符是 自动附加。
返回的数组指向 内部位置与所需 这个序列的存储空间 字符加上终止 null-character,但是这里的值 不应该修改数组 程序,只被授予保留 直到下一次打电话给a 非常数成员函数 字符串对象。
他们为什么不定义operator const char*() const {return c_str();}
?
答案 0 :(得分:22)
从C ++编程语言20.3.7(强调我的):
转换为C风格的字符串可能是由运算符const char *()而不是c_str()提供的。这样可以提供隐式转换的便利性,但这种转换出乎意料的情况会出现意外。
答案 1 :(得分:15)
我发现隐式转换至少存在两个问题:
即使c_str()
提供的显式转换也足够危险。我已经看到很多情况下指针存储在原始字符串对象的生命周期结束后使用(或者对象被修改从而使指针无效)。通过显式调用c_str()
,您希望了解这些问题。但是通过隐式转换,很容易导致未定义的行为,如:
const char *filename = string("/tmp/") + name;
ofstream tmpfile(filename); // UB
转换也会发生在某些情况下,你会发现它并不令人惊讶,至少可以说:
string name;
if (name) // always true
;
name-2; // pointer arithmetic + UB
这些可以通过某种方式避免,但为什么要首先陷入这个麻烦?
答案 2 :(得分:5)
Josuttis的书中说明如下:
出于安全原因,这是为了防止导致奇怪行为的意外类型转换(类型
char *
通常具有奇怪的行为)和歧义(例如,在组合string
和C的表达式中-string可以将string
转换为char *
,反之亦然。)
答案 3 :(得分:4)
因为隐式转换几乎从不像您期望的那样表现。它们可以在重载决策中给出令人惊讶的结果,因此通常 更好地提供std :: string的显式转换。
答案 4 :(得分:3)
除了规范中提供的基本原理(意外的惊喜)之外,如果你将C API调用与std :: string混合,你真的需要养成使用:: c_ctr()方法的习惯。如果你曾经调用过一个需要const char *的varargs函数(例如:printf或者等价函数),并且你直接传递了一个std :: string(没有调用提取方法),你就不会遇到编译错误(没有类型)检查varargs函数),但是你会得到一个运行时错误(类布局与const char *不是二进制文件)。
顺便提一下,CString(在MFC中)采用相反的方法:它具有隐式转换,并且类布局与const char *(或const w_char *,如果编译宽字符串,即:“Unicode”二进制兼容“)。
答案 5 :(得分:2)
这可能是因为这种转换会产生令人惊讶和特殊的语义。特别是你引用的第四段。
另一个原因是存在隐式转换const char* -> string
,这只是反过来,这意味着过载解决的奇怪行为(你不应该进行隐式转换A->B
和{ {1}})。
答案 6 :(得分:1)
因为C风格的字符串是错误的来源和许多安全问题,所以明确地进行转换会更好。