c++ - 为什么 std::string 没有(明确的)const char* cast

标签 c++ c++11 casting std stdstring

我想知道拥有和不拥有这样的 Actor 阵容的优缺点。在包括此处 Stack Overflow 在内的几个地方,我可以看到 const char* cast 被认为是个坏主意,但我不确定为什么?

缺少 (const char*) 并强制始终使用 c_str() 转换会在编写通用例程和模板时产生一些问题。

void CheckStr(const char* s)
{
}

int main()
{
    std::string s = "Hello World!";

    // all below will not compile with 
    // Error: No suitable conversion function from "std::string" to "const char *" exists!
    //CheckStr(s);             
    //CheckStr((const char*)s);  
    // strlen(s);

    // the only way that works
    CheckStr(s.c_str());
    size_t n = strlen(s.c_str());
    return 0;
}

例如,如果我有大量接受 const char* 作为输入的文本处理函数,并且我希望每个函数都能使用 std::string是时候我必须使用 c_str() 了。但是通过这种方式,模板函数不能同时用于 std::stringconst char* 而不需要额外的努力。

作为一个问题,我可以看到一些运算符重载问题,但这些问题是可以解决的。

例如,正如 [eerorika] 指出的那样,通过允许隐式转换为指针,我们允许非自愿的字符串类参与 bool 表达式。但是我们可以通过删除 bool 运算符轻松解决这个问题。更进一步,可以强制转换运算符是显式的:

class String
{
public:
    String() {}
    String(const char* s) { m_str = s; }
    const char* str() const  { return m_str.c_str(); }
    char* str()  { return &m_str[0]; }
    char operator[](int pos) const { return m_str[pos]; }
    char& operator[](int pos) { return m_str[pos]; }
    explicit operator const char*() const { return str(); }  // cast operator
    operator bool() const = delete;

protected:
    std::string m_str;
};

int main()
{
    String s = "Hello";
    string s2 = "Hello";
    if(s)  // will not compile:  it is a deleted function
    {
        cout << "Bool is allowed " << endl;
    }

    CheckStr((const char*)s);
    return 0;
}

最佳答案

I like to know pro's and con's for having and not-having such cast.

缺点:隐式转换的行为通常会让程序员感到惊讶。

例如,您希望从以下程序中得到什么?

std::string some_string = "";
if (some_string)
    std::cout << "true";
else
    std::cout << "false";

程序是否应该格式错误,因为 std::string 没有转换为 bool?结果应该取决于字符串的内容吗?大多数程序员会有同样的期望吗?

对于当前的 std::string,上面的格式是错误的,因为没有这样的转换。这很好。无论程序员期望什么,他们都会在尝试编译时发现自己的误解。

如果 std::string 有一个到指针的转换,那么也会有一个转换序列通过到指针的转换来 bool。上面的程序是良构的。无论字符串的内容如何,​​程序都会打印 true,因为 c_str 永远不会为 null。如果程序员反而期望空字符串为假怎么办?如果他们从来没有打算采取任何一种行为,而是无意中使用了一个字符串怎么办?

下面的程序呢?

std::string some_string = "";
std::cout << some_string + 42;

您是否认为程序是病式的,因为字符串和 int 没有这样的运算符?

如果存在到 char* 的隐式转换,则上述代码将具有未定义的行为,因为它进行指针运算并访问其边界之外的字符串缓冲区。


// all below will not compile with 
strlen(s);

这其实是一件好事。大多数时候,您不想调用 strlen(s)。通常,您应该使用 s.size(),因为它渐近地更快。对 strlen(s.c_str()) 的需求是如此罕见,以至于一点点冗长都是微不足道的。

强制使用 .c_str() 很棒,因为它向程序的读者表明传递给函数的不是 std::string/运算符,而是一个 char*。使用隐式转换,无法将两者区分开来。


... creates some problems when writing generic routines and templates.

这些问题并非无法克服。

关于c++ - 为什么 std::string 没有(明确的)const char* cast,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59076004/

相关文章:

c++ - 我可以将什么用作 NULL 结构?

c++ - 插入排序怎么写

c++ - 访问共享内存进行读取时锁定

linux - 什么时候在 std::thread 上调用 native_handle() 是安全的?

转换指针 - 运行时有什么区别?

将 void** 转换为 int 的二维数组 - C

c++ - 仿函数的线程与解构

c++ - 为什么 std::unique_ptr 不允许类型推断?

c++ - 为什么在这种情况下不会调用移动构造函数?

c++ - 使用 reinterpret_cast 序列化和反序列化数据