简体   繁体   English

为什么 std::string 没有(显式) const char* 强制转换

[英]Why std::string does not have (explicit) const char* cast

I like to know pro's and con's for having and not-having such cast.我想知道有和没有这样的演员的优点和缺点。 At several places including here on Stack Overflow I can see that the const char* cast is considered bad idea but I am not sure why?在包括 Stack Overflow 在内的几个地方,我可以看到const char*被认为是个坏主意,但我不知道为什么?

Lack of the (const char*) and forcing to always use c_str() cast creates some problems when writing generic routines and templates.在编写通用例程和模板时,缺少(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;
}

For example, if I have a large number of text processing functions that accept const char* as input and I want to be able to use std::string each time I have to use c_str() .例如,如果我有大量接受const char*作为输入的文本处理函数,并且我希望每次必须使用c_str()时都能够使用std::string But in this way a template function can't be used for both std::string and const char* without additional efforts.但是通过这种方式,模板函数不能同时用于std::stringconst char*而不需要额外的努力。

As a problem I can see some operator overloading issues but these are possible to solve.作为一个问题,我可以看到一些运算符重载问题,但这些都是可以解决的。

For example, as [eerorika] pointed, with allowing implicit cast to pointer we are allowing involuntary the string class to be involved in boolean expressions.例如,正如 [eerorika] 所指出的,通过允许隐式转换为指针,我们允许字符串类不自觉地参与布尔表达式。 But we can easily solve this with deleting the bool operator.但是我们可以通过删除 bool 运算符轻松解决这个问题。 Even further, the cast operator can be forced to be explicit:更进一步,可以强制强制转换运算符显式:

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.我想知道有和没有这样的演员的优点和缺点。

Con: Implicit conversions often have behaviour that is surprising to the programmer.缺点:隐式转换通常具有令程序员感到惊讶的行为。

For example, what would you expect from following program?例如,您对以下程序有何期望?

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

Should the program be ill-formed because std::string is has no conversion to bool ?程序是否应该std::string因为std::string没有转换为bool Should the result depend on the content of the string?结果应该取决于字符串的内容吗? Would most programmers have the same expectation?大多数程序员会有同样的期望吗?

With the current std::string , the above would be ill-formed because there is no such conversion.使用当前的std::string ,由于没有这样的转换,上述内容将是std::string的。 This is good.这很好。 Whatever the programmer expected, they'll find out their misunderstanding when they attempt to compile.无论程序员期望什么,他们都会在尝试编译时发现他们的误解。

If std::string had a conversion to a pointer, then there would also be a conversion sequence to bool through the conversion to pointer.如果std::string转换为指针,那么也会有一个转换序列通过转换为指针来 bool。 The above program would be well-formed.上面的程序将是格式良好的。 And the program would print true regardless of the content of the string, since c_str is never null.无论字符串的内容如何,​​程序都会打印true ,因为c_str永远不会为空。 What if programmer instead expected that empty string would be false?如果程序员期望空字符串为假怎么办? What if they never intended either behaviour, but used a string there by accident?如果他们从来没有打算过任何一种行为,而是不小心在那里使用了一个字符串怎么办?

What about the following program?下面的程序呢?

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

Would you expect the program to be ill-formed because there is no such operator for string and int ?您是否希望程序格式错误,因为 string 和int没有这样的运算符?

If there was implicit conversion to char* , the above would have undefined behaviour because it does pointer arithmetic and accesses the string buffer outside of its bounds.如果隐式转换为char* ,则上述行为将具有未定义的行为,因为它执行指针算术并访问超出其边界的字符串缓冲区。


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

This is actually a good thing.这其实是一件好事。 Most of the time, you don't want to call strlen(s) .大多数情况下,您不想调用strlen(s) Usually, you should use s.size() because it is asymptotically faster.通常,您应该使用s.size()因为它渐近地更快。 The need for strlen(s.c_str()) is so rare, that the little bit of verbosity is insignificant.strlen(s.c_str())是如此罕见,以至于一点点冗长都无关紧要。

Forcing the use of .c_str() is great because it shows the reader of the program that it is not a std::string that is passed to the function / operator, but a char* .强制使用.c_str()很棒,因为它向程序的读者展示了它不是传递给函数/运算符的std::string ,而是char* With implicit conversion, it is not possible to distinguish one from the other.使用隐式转换,无法将两者区分开来。


... creates some problems when writing generic routines and templates. ...在编写通用例程和模板时会产生一些问题。

Such problems are not insurmountable.此类问题并非不可克服。

If by "having a cast" you mean a user defined conversion operator , then the reason it does not have it is: to prevent you from using it implicitly, possibly inadvertently.如果“进行强制转换”是指用户定义的转换运算符,那么它没有的原因是:防止您隐式使用它,可能是无意中使用它。

Historically, unpleasant consequences of an inadvertent use of such conversion stem the fact that in the original std::string (per C++98 specification) the operation was heavy and dangerous .从历史上看,无意中使用此类转换会产生令人不快的后果,因为在原始std::string (根据 C++98 规范)中,该操作是繁重危险的

  • The original std::string was not trivially convertible to const char * , since the string object was not originally intended/required to store a null-terminator character.原始std::string不能简单地转换为const char * ,因为 string 对象最初不是打算/需要存储空终止符。 Under those circumstances, conversion to const char * was a potentially heavy operation that generally allocated an independent buffer and copied the entire controlled sequence to that buffer.在这些情况下,转换为const char *是一项潜在的繁重操作,通常会分配一个独立的缓冲区并将整个受控序列复制到该缓冲区。

  • The independent buffer mentioned above (if used) had potentially "unexpected" lifetime.上面提到的独立缓冲区(如果使用)具有潜在的“意外”寿命。 Any modifying operation on the original std::string object triggered invalidation/deallocation of that buffer, rendering previously returned pointers invalid.对原始std::string对象的任何修改操作都会触发该缓冲区的无效/解除分配,从而使先前返回的指针无效。

It is never a good idea to implement such heavy and dangerous operations as implicitly-invokable conversion operators.实现像隐式可调用转换运算符这样繁重而危险的操作从来都不是一个好主意。

The original C++ standard (C++98) did not have such feature as explicit conversion operators.最初的 C++ 标准 (C++98) 没有explicit转换运算符这样的特性。 (They first appeared in C++11.) A dedicated named member function was the only way to somehow make the conversion explicit in C++98. (它们首次出现在 C++11 中。)专用的命名成员函数是在 C++98 中以某种方式使转换显式的唯一方法。

Today, in modern C++, we can define a conversion operator and still prevent it from being used implicitly (by using explicit keyword).今天,在现代 C++ 中,我们可以定义一个转换运算符,并且仍然可以防止它被隐式使用(通过使用explicit关键字)。 One can argue that under such circumstances implementing the conversion by an operator is a reasonable approach.可以争辩说,在这种情况下,由运营商实施转换是一种合理的方法。 But I'd still argue that it is not a good idea.但我仍然认为这不是一个好主意。 Even though the modern std::string is required to store its null-terminator (ie c_str() no longer produces an independent buffer), the pointer returned by the conversion to const char * is still "dangerous": many modification operations applied to std::string object may (and will) invalidate this pointer.即使现代std::string需要存储其空终止符(即c_str()不再产生独立的缓冲区),转换为const char *返回的指针仍然是“危险的”:许多修改操作应用于std::string对象可能(并将)使该指针无效。 To emphasize the fact that this is not a mere safe and innocent conversion, but rather an operation that produces a potentially dangerous pointer, it is quite reasonable to implement it by a named function.为了强调这样一个事实,即这不仅仅是一个安全无害的转换,而是一个产生潜在危险指针的操作,通过命名函数实现它是非常合理的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么const char *强制转换为std :: string有效? - Why does a const char* cast to std::string work? 使用const cast将标准字符串转换为char * - Converting a std string to char* using const cast std :: string生成链接器错误-const char *不会。 为什么? - std::string generates linker error — const char* does not. why? 为什么std :: string不提供到const char *的转换? - Why does std::string not provide a conversion to const char*? 为什么“auto”将字符串声明为const char *而不是std :: string? - Why does “auto” declare strings as const char* instead of std::string? 为什么std :: runtime_error :: what()返回const char *而不是std :: string const& - Why does std::runtime_error::what() return const char* instead of std::string const& 为什么此函数将&#39;const char *&#39;强制转换为&#39;void * const&#39;而不是&#39;const void *&#39; - Why does this function cast 'const char*' to 'void* const' and not 'const void*' 为什么std :: string {“ const char ptr”}有效? - Why std::string{“const char ptr”} works? 为什么 const char[] 与 std::ranges::range 的匹配比显式的 const char* 自由重载更好,以及如何修复它? - Why is const char[] a better match for std::ranges::range than for an explicit, const char* free overload, and how to fix it? std :: string和const char * - std::string and const char *
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM