【问题标题】:C++ constructors and implicit string conversionC++ 构造函数和隐式字符串转换
【发布时间】:2014-07-26 20:37:47
【问题描述】:

在 C++ 中,我可以编写一个带有 std::string 参数的构造函数的类。由于隐式转换,这将允许我从 std::stringchar * 构造此类的实例。

有没有理由同时拥有std::string 构造函数和char * 构造函数?

class MyStringClass {
 public:
    MyStringClass( const std::string &str ); // char *'s could implicitly use this constructor
    MyStringClass( const char * str );       // would this ever be necessary?
};

这个问题也适用于函数参数。

void do_stuff_with_string( const std::string &str );
void do_stuff_with_string( const char * str );

编辑:

为了澄清,我想知道更多关于性能的信息。假设这些构造函数/函数正在调用只接受char * 的api。如果我不需要的话,是否值得拥有两个独立的函数来避免构造 std::string

void do_stuff_with_string( const std::string &str )
{
    do_stuff_with_string( str.c_str() );
}

void do_stuff_with_string( const char * str )
{
    // call some api that only accepts char *
}

【问题讨论】:

  • 显而易见的原因是如果您想以不同的方式处理它们。当然,还有其他原因,如果不简单地提供一个清单,就很难回答这个问题。你能告诉我们更多关于你想要做什么的信息吗?
  • @CodyGray 我想我更多地询问性能方面的问题。是否值得同时避免构造一个字符串(如果在函数内部我只使用 .c_str() 方法,例如),还是开销如此之小我不应该担心?
  • @CodyGray 正如您自己指出的那样,您保存的是字符串的构造。该开销是否“分钟”取决于该类在您的程序中的使用方式,因此通常很难在这里回答。
  • 如果你有一个 const char* 字符串,那么这绝对是一个有问题的设计,然后创建(通过隐式转换)一个 const std::string& from它,并最终通过 std::string::c_str() 将其传递给具有 const char* 接口的某些 C-API。有关详细信息,请参阅下面的答案。

标签: c++ string function class implicit-conversion


【解决方案1】:

如果您正在使用需要 (const) char* 函数参数的 C API,您通常(也)希望提供 (const) char* C - 风格的界面。

例如,想想 iconv(3) 的 RAII 包装器 Iconv。在 Iconv 的 初始化中,您需要包装

iconv_t iconv_open(const char* tocode, const char* fromcode);

你真的希望 Iconv 的(唯一的)构造函数是

Iconv(const std::string& tocode, const std::string& fromcode);

尤其是如果您的参数(tocode、fromcode)很可能来自命令行 (argv)?

在这种情况下,我将定义相应的 C 样式构造函数,并且可能还定义前面的一个(然后通过 std::string::c_str() 调用 C 样式构造函数)。

【讨论】:

    【解决方案2】:

    如果您希望以不同方式处理 C 字符串和 std::string,则需要重载构造函数。

    MyStringClass::MyStringClass( const std::string &str )
    {
        // Do std::string-specific stuff here.
    }
    
    MyStringClass::MyStringClass(const char * str )
    {
        // Do char* specific stuff here.
    }
    

    const char * 的参数也有可能不是以空字符结尾的 C 字符串,而实际上是指向单个字符的指针,或非以空字符结尾的字符数组。在这种情况下,隐式转换可能会失败。

    例子:

    #include <iostream>
    
    int DoStuff(const std::string &myString)
    {
        std::cout << myString << std::endl;
    }
    
    int main()
    {
        DoStuff("This is a null terminated c-string");  // Fine!
    
        char charArray[] = { 'A', 'B', 'C' };           // Not null terminated!
        DoStuff(charArray);                             // Uh oh!
    }
    

    上面的例子是针对一个函数的,但同样也可以应用于构造函数。上面的例子编译没有警告!

    在性能方面,由于std::string(const char * const) 构造函数会将 c 字符串复制到它自己的内部缓冲区中,因此肯定会受到影响。然而,在大多数情况下,影响可以忽略不计,因为复制非常有效。但是,对于非常大的字符串,这可能是个问题。

    不过,作为一般规则,请尽量使用 C++ 字符串,并在需要 C 样式字符串时使用 std::string::c_str() 成员。在大多数情况下,从char*std::string 的偶尔字符串复制将是一个微优化。只有在性能非常关键的代码中,这才是潜在的问题。

    【讨论】:

    • 最后一个例子是// Uh oh!无论如何。由于您没有将数组的长度作为参数传递,因此您将立即阅读。函数知道它的唯一方法是定位一个标记字符。然后你就重新发明了 C 风格的字符串。
    • @CodyGray - 技术上正确(最好的正确)!我的观点是char * 不一定必须是 c 字符串,在这些情况下需要重载,在后一种情况下需要长度参数。
    【解决方案3】:

    是的,假设您想从构造函数中释放char * 字符串所持有的内存。在这种情况下,您需要两个不同的构造函数。

    【讨论】:

      猜你喜欢
      • 2013-11-02
      • 2014-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-18
      • 1970-01-01
      • 2020-06-20
      相关资源
      最近更新 更多