【问题标题】:Why does std::string not provide a conversion to const char*?为什么 std::string 不提供到 const char* 的转换?
【发布时间】:2010-11-04 11:33:41
【问题描述】:

这更多是一个政策或历史问题。为什么决定为 std::string 提供 const char * 转换?是否担心有人会执行 printf("%s", s) 并相信它会自动转换?有没有关于这个问题的公开讨论?

【问题讨论】:

    标签: c++ string implicit-conversion


    【解决方案1】:

    自动施法几乎总是邪恶的。如果转换为const char *std::string 也可以自动转换为其他指针类型,这可能导致难以找到错误。有c_str() 方法返回const char *,所以你仍然可以实现你所需要的。此外,类型转换在逻辑上不正确 - std::string 不等于 const char *

    【讨论】:

    • +1:同意。即使在标准库中,也有可怕的强制重载的例子。例如,考虑std::ios::operator void*
    • +1,如果字符串被破坏,指针会指向什么?
    • @dark_charlie - 如果演员阵容会导致问题,那么一个 .c_str() 也会导致问题,因为我希望它们是等效的。无论如何,您是说这是两害相权取其轻……多年来,我一直在使用具有自动转换功能的派生类,但我还没有因此而出现任何错误。但也许这是因为我没有使用带有敏捷 Boost 类的通用模板元编程。 :-)
    • @dov:如果您知道自己在做什么并自己编写派生字符串类,那么这可能不是问题。但在标准中包含此功能意味着每个人都拥有这种投射功能 - 并不是每个人都意识到自动投射的陷阱,没有注意到@edA-qa mort-ora-y 所描述的可能出现的性能问题。
    • @Oli:虽然该特定示例可以追溯到安全布尔成语被理解之前,并且这种使用类型在 0x 中被显式运算符 bool 替换。
    【解决方案2】:

    字符串类在内部不需要存储以 0 结尾的字符串。事实上,如果它不想将它们存储在连续的内存中,它甚至不必存储它们。因此,隐式转换没有意义,因为它可能是一项昂贵的操作。

    c_str() 函数然后为您提供 c 字符串。根据库内部存储它的方式,此函数可能必须创建一个临时函数。此临时文件仅在您修改字符串之前有效。

    不幸的是,因为字符串可以在内部被指定为 c 字符串。这不会导致任何功能损失,并允许隐式转换。

    编辑 该标准基本上暗示内存是连续的(如果通过 data() 或 [] 运算符访问),尽管它不需要在内部,当然也不是以空值终止的。可能所有实现也存储 0。如果这是标准化的,那么可以安全地定义隐式转换。

    【讨论】:

    • 其实我认为字符串类作为向量,必须要作为持续内存存储。
    • +1。这比 dark_charlie 的回答要好。创建一个具有重要生命周期问题的临时对象比一些令人惊讶的演员表更重要。
    • @Viktor:不。与std::vector(C++03 引入了该要求)不同,std::string 在调用c_str() 之前不必使用连续存储。然后当然返回的指针必须指向连续存储。我隐约记得 C++0x WG 进行了一次草率投票的报告(可能来自 Herb Sutter?),在场的人都不知道有一个总是使用连续存储的活动实现。跨度>
    • 允许非连续内部存储的基本原理可以追溯到字符串使用共享 COW 缓冲区的时候。这样做的目的是提高效率,因为它减少了内存副本的数量,但线程争用问题使得它在现实中通常效率较低并且更难实现。使用 COW 缓冲区,如果您将两个字符串添加在一起,您可以暂时使用“绳索”实现,直到有人对其调用 c_str() 或对其进行写入。如果用户正在执行大量 + 操作,大多数将是临时的,他们将永远不会执行其中任何一个,并且将有 1 个最终副本。
    • @Roger,再次阅读标准我同意它必须是连续的:str[n] 被定义为 str.data()[n]。此外,一些构造函数要求 data() 是连续的。
    【解决方案3】:

    关于你以前的cmets:

    如果它们是等价的,那么使用 cast 代替 c_str() 调用没有区别(除了方便)

    有一个非常重要的区别:一个是隐式的,另一个是显式的。

    C++0x 引入了explicit 强制转换运算符的概念,但在此之前它们是隐式的,这意味着永远不清楚(查看代码时)是否会使用它们。

    隐式转换很糟糕,尤其是因为它们可以级​​联,导致代码极其晦涩。

    此外,如前所述,这里存在正确性问题。因为c_str 返回的指针只有在string 对象不变的情况下才有效,所以你会发现自己很难找到错误。考虑:

    void function()
    {
      std::map<int, char const*> map;
    
      map[1] = boost::lexical_cast<std::string>(47);
    
      std::cout << map[1] << std::endl; // CRASH here, if lucky...
    }
    

    【讨论】:

      【解决方案4】:

      我的感觉是 C++ 是一种强类型语言,隐式类型转换破坏了类型安全。

      它通常会在转换发生在你意想不到的地方给你带来麻烦,并且会使你的代码难以调试。

      非显式构造函数可以具有类似的效果,并且 std::string 本身确实具有来自 const char * 的隐式构造函数。在这种情况下,它不一定是一件坏事,尽管它会导致代码效率低下。

      【讨论】:

        猜你喜欢
        • 2010-10-04
        • 2018-08-23
        • 1970-01-01
        • 2021-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多