为什么std :: string没有const char *类型转换

Baj*_*ile 0 c++ casting std stdstring c++11

我喜欢了解赞成与反对者拥有和不拥有这样的演员。在包括Stack Overflow在内的多个地方,我可以看到const char*强制转换被认为是一个坏主意,但我不确定为什么吗?

编写通用例程和模板时,缺少(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;
}
Run Code Online (Sandbox Code Playgroud)

例如,如果我有大量接受const char*输入的文本处理功能,并且我希望std::string每次使用都能够使用c_str()。但是以这种方式std::stringconst char*如果没有额外的努力,模板函数就不能同时使用。

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

例如,正如[eerorika]指出的那样,通过允许隐式强制转换为指针,我们允许将非自愿的字符串类包含在布尔表达式中。但是我们可以通过删除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;
}
Run Code Online (Sandbox Code Playgroud)

eer*_*ika 6

我喜欢了解赞成与反对者拥有和不拥有这样的演员。

缺点:隐式转换通常具有令程序员惊讶的行为。

例如,您对以下程序会有什么期望?

std::string some_string = "";
if (some_string)
    std::cout << "true";
else
    std::cout << "false";
Run Code Online (Sandbox Code Playgroud)

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

使用current std::string,由于没有这样的转换,因此上述内容将格式错误。很好 不管程序员期望什么,他们在尝试编译时都会发现自己的误解。

如果std::string对指针进行了转换,那么还将存在一个转换序列,以通过对指针的转换来实现转换。上面的程序格式正确。并且程序将打印true而不管字符串的内容如何,​​因为c_str它永远不会为null。如果程序员反而希望空字符串为假,该怎么办?如果他们既不想使用任何行为,又无意间在其中使用了字符串怎么办?

接下来的程序呢?

std::string some_string = "";
std::cout << some_string + 42;
Run Code Online (Sandbox Code Playgroud)

您是否希望该程序格式错误,因为没有用于string和的运算符int

如果存在对的隐式转换char*,则以上内容将具有未定义的行为,因为它执行指针算术并访问其边界之外的字符串缓冲区。


// all below will not compile with 
strlen(s);
Run Code Online (Sandbox Code Playgroud)

这实际上是一件好事。大多数情况下,您不想打电话strlen(s)。通常,应该使用s.size()它,因为它渐近地更快。对需求的需求strlen(s.c_str())如此之少,以至于冗长的一点点微不足道。

强制使用.c_str()之所以很棒,是因为它向程序的读者显示,它不是std::string传递给函数/运算符的,而是传递给的char*。使用隐式转换时,不可能将一个与另一个区分开。


在编写通用例程和模板时会产生一些问题。

这样的问题不是无法克服的。