【问题标题】:Is implicit construction of `const std::string` from `const char *` efficient?从 `const char *` 隐式构造 `const std::string` 有效吗?
【发布时间】:2020-08-20 16:27:00
【问题描述】:

像许多人一样,我习惯于将新的字符串函数编写为const std::string & 的函数。优点是效率(您可以传递现有的std::string 对象,而不会产生复制/移动的开销)和灵活性/可读性(如果您只有const char *,您可以传递它并隐式完成构造,而不会造成混乱您的代码具有显式 std::string 构造):

#include <string>
#include <iostream>
unsigned int LengthOfStringlikeObject(const std::string & s)
{
    return s.length();
}
int main(int argc, const char * argv[])
{
    unsigned int n = LengthOfStringlikeObject(argv[0]);
    std::cout << "'" << argv[0] << "' has " << n << " characters\n";
}

我的目标是编写能够有效处理长字符串的高效跨平台代码。我的问题是,在隐式构造过程中会发生什么?是否有任何保证不会复制字符串?令我震惊的是,因为一切都是const,所以不需要复制——只需要一个围绕现有指针的薄 STL 包装器——但我不确定我应该如何依赖编译器和平台.始终显式编写两个版本的函数会更安全吗,一个用于const std::string &amp;,一个用于const char *

【问题讨论】:

  • 你不能总是用std::strings 代替char * 吗?我的意思是argv[0] 只能复制一次到std::string,其余的都可以是std::string
  • @idclev463035818 假设它可能是一个非常大的字符串,我想避免在内存中复制它,即使在开始时也是如此。
  • 我写了两个函数(或成员函数)以防我想避免复制 const char *。但这些情况是有限的。我想答案取决于有多少功能需要这个?

标签: c++ string stl constants implicit-constructor


【解决方案1】:

令我震惊的是,因为一切都是 const,所以复制不是 必要的——围绕现有指针的薄 STL 包装器就是全部 需要

我不认为这个假设是正确的。仅仅因为您有一个指向 const 的指针,并不意味着基础值不能改变。它仅意味着无法通过该指针更改值。指针可能指向可以随时更改的非常量存储。

因此,库必须制作自己的副本(以提供“正确”的字符串可观察行为)。对 libstdc++ 的快速回顾表明它总是制作副本。 char* 的构造不是内联的,因此如果没有静态链接和 LTO,就无法对其进行优化。

虽然极其微不足道的静态链接程序可能会使用 LTO 优化副本(我无法重现这一点),但我认为通常不太可能执行这种优化(特别是考虑到 @987654322 的别名规则@)。 g++ 甚至不会对字符串文字执行这种优化。

【讨论】:

  • 对,我没有意识到这一点。传递 const 参数是在说“我需要 you 不要弄乱这些数据”,但它不能保证“I 不会弄乱这些数据”。其他答案非常有用——我了解到string_view 是我所期待的行为的名称,并被提醒坚持是它的关键问题——但这种对 STL 观点的洞察提供了真正的面子时刻。跨度>
【解决方案2】:

如果你不想复制,那么string_view就是你想要的。

然而,这个好处也带来了问题。具体来说,您必须确保您传递的存储持续“足够长”。

对于字符串文字,这没问题。对于argv[0],这几乎肯定不是问题。对于任意字符序列,您需要考虑它们。

但你可以写:

unsigned int LengthOfStringlikeObject(std::string_view sv)
{
    return sv.length();
}

并用stringconst char * 调用它,就可以了。

【讨论】:

    【解决方案3】:

    如果您将const char* 传递给采用std::string 的对象,无论是否引用,都会构造一个字符串。如果您将它发送到带有隐式临时对象警告的引用,编译器甚至可能会抱怨。

    现在这可能会被编译器优化,而且一些实现不会为小字符串分配内存。编译器还可能在内部对其进行优化以使用 C++17 string_view。它本质上取决于您将对代码中的字符串做什么。如果只使用常量成员函数,聪明的编译器可能会优化出来。

    但这取决于实施,不在您的控制范围内。如果你想接管,你可以明确使用std::string_view

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-10-22
      • 1970-01-01
      • 2011-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多