【问题标题】:Should I compare a std::string to "string" or "string"s?我应该将 std::string 与“string”还是“string”进行比较?
【发布时间】:2019-10-19 00:35:06
【问题描述】:

考虑这段代码sn-p:

bool foo(const std::string& s) {
    return s == "hello"; // comparing against a const char* literal
}

bool bar(const std::string& s) {
    return s == "hello"s; // comparing against a std::string literal
}

first sight,与const char* 进行比较似乎需要更少的汇编指令1,因为使用字符串文字将导致std::string 的就地构造。

(编辑:正如答案中指出的那样,我忘记了s.compare(const char*) 将在foo() 中被调用的事实,所以在这种情况下当然不会发生就地构造. 因此删除下面的一些行。)

不过,看着operator==(const char*, const std::string&) reference:

所有比较都是通过compare() 成员函数完成的。

根据我的理解,这意味着我们无论如何都需要构造一个std::string 来执行比较,所以我怀疑开销最终会是相同的(尽管通过调用operator== 隐藏了) .

  • 我应该更喜欢哪个比较?
  • 一个版本是否比另一个版本有优势(可能在特定情况下)?

1我知道,更少的汇编指令并不一定意味着更快的代码,但我不想在这里进行微基准测试。

【问题讨论】:

  • return s == "hello";.
  • 最好使用-O2/3 进行比较,我的意思是谁在乎它在调试版本中有多少条指令? ;)
  • @Someprogrammerdude 不,不是。这是不编写不必要的浪费代码的情况。字符串文字和不必要的字符串实例化之间的选择不是微优化。这是常识!换句话说,这关于编写好的代码。
  • 目前世界上有太多臃肿和缓慢的代码,因为人们认为编写不需要做更多事情的好代码是“过早的优化”并且被吓跑了考虑到他们正在编写的代码结果:(
  • @Someprogrammerdude 这与过早优化没有任何关系,我一开始是出于好奇而问的,这也会在一定程度上影响编码风格.在一般情况下,您不会告诉人们通过 const Aconst A&,只是因为他们不应该关心“过早优化”

标签: c++ c++14 c++17 string-comparison string-literals


【解决方案1】:

都没有。

如果你想更聪明,请与 "string"sv 比较,后者返回 std::string_view


虽然与 "string" 之类的字面值进行比较不会产生任何分配开销,但它被视为以空字符结尾的字符串,并具有所有伴随的缺点:不能容忍嵌入的空值,用户必须注意空值终止符。

"string"s 进行分配,但 small-string-optimisationallocation elision 除外。此外,运算符会传递文字的长度,无需计数,并且允许嵌入空值。

最后使用"string"sv 结合了其他两种方法的优点,避免了它们各自的缺点。此外,std::string_viewstd::string 简单得多,特别是如果后者像所有现代的一样使用 SSO。


至少从 C++14(通常允许省略分配)开始,编译器理论上可以优化最后一个选项的所有选项,只要提供足够的信息(通常可用于示例)和努力,在 as-if rule 下。不过我们还没有。

【讨论】:

  • @xception 是的。不幸的是,该标准几乎没有充分的理由(而不是仅仅列出重载及其简单参数的老式方法)以令人难以置信的奥秘术语谈论新的重载。但你要找的是7-9 here
  • 对不起,这比简单的字符串文字有什么好处?不要误会我的意思,我喜欢字符串视图并在适当的时候明智地使用它们,但我在这里没有看到它。
  • 事实上,使用-O3 gcc 似乎甚至可以使用inline the call to compare,这在常规字符串文字中不会发生。
  • @LightnessRacesinOrbit 没有strlen() 用于使用operator "" sv 创建string_view。
  • gcc9.1 -Ofast 上使用 string_view looks 最快,因为内联调用比较。使用-Os,string_view 和字符串文字版本都调用memcmp
【解决方案2】:

不,compare() 不需要为 const char* 操作数构造 std::string

您正在使用overload #4 here

与字符串文字的比较是您正在寻找的“免费”版本。在这里实例化 std::string 是完全没有必要的。

【讨论】:

  • “免费”仅当合适的 compare 函数的实现本身不创建 std::string 对象时(尽管这可能不太可能)。
  • @Someprogrammerdude 在这个抽象级别上是免费的,是的。从理论上讲,该实现可以设计为与云进行比较,从而导致数毫秒的延迟并可能登录到 Facebook - 但让我们成为现实;)
  • (但这确实是我使用引号的原因,因为没有什么是真正免费的)
  • 嗯,也许我在这里遗漏/忽略了一些东西,但是如果compare 是一个成员函数(非静态),它不需要如何需要构造一个std::string ?
  • 好的,我明白了。 “与字符串文字的比较是您正在寻找的“免费”版本。”:通过字符串文字,您似乎在谈论普通的旧 C 文字,而我在想std::string_literals。这可能是问题:-)
【解决方案3】:

根据我的理解,这意味着我们无论如何都需要构造一个std::string 来执行比较,所以我怀疑开销最终会是相同的(尽管通过调用operator== 隐藏了) .

这就是推理出错的地方。 std::compare 不需要将其操作数分配为 C 风格的以空字符结尾的字符串来运行。根据其中一个重载:

int compare( const CharT* s ) const; // (4)

4) 将此字符串与从s 指向的字符开始、长度为Traits::length(s) 的空终止字符序列进行比较。

虽然是否分配是一个实现细节,但序列比较这样做似乎并不合理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-16
    • 1970-01-01
    相关资源
    最近更新 更多