【问题标题】:NRVO for C++ std::stringNRVO for C++ std::string
【发布时间】:2019-06-03 11:15:34
【问题描述】:

我尝试查找有关 std::string 命名返回值优化 (NVRO) 的一些信息。 我什至不确定这是否适用,但我想知道从可读性和性能 POV 来看哪个会更好。

std::string first(const bool condition)
{
    std::string info = "This";
    info += condition 
        ? " is" 
        : " irrelevant";  //.append()

    info += " info.";

    return info; // nrvo here?
}

std::string second(const bool condition)
{
    const auto firstPart = "First part";
    const auto anotherPart = condition 
        ? " second part" 
        : " irrelevant ";  //.append()

    return std::string{}.append(firstPart).append(anotherPart);
}

std::string third(const bool condition)
{
    //would avoid due to poor readability if strings are long
    return std::string{}
        .append("First part")
        .append(condition ? " second" : "irrelevant");
}

int main()
{
    // printf("Hello World");
    const auto irrelevant {true};

    std::cout<<first(irrelevant)<<std::endl;
    std::cout<<second(irrelevant)<<std::endl;
    std::cout<<third(irrelevant)<<std::endl;

    return 0;
}

在 cmets 中:

  1. nvro 会在“frist”中执行吗?

  2. 有没有更好(更清洁/性能)的方法来解决这个问题?

我的目的是创建一个辅助函数,它将根据给定的参数连接正确的字符串

【问题讨论】:

  • 1.编译器可以在那个地方使用 RVO。
  • @MichalP 此问题仍列为未回答。没有任何建议的答案可以解决问题吗?

标签: c++ c++14 nrvo


【解决方案1】:
  1. 在 C++11 和 14 中,copy elision 在这种情况下是允许的。从 C++17 开始,返回值优化是强制性的(不再被视为复制省略)。

  2. 不是我可以通过查看三个候选函数@godbolt 看到的,但我不会做太多的汇编程序。不过,这可能看起来更干净一些:

    std::string fourth(const bool condition) {
        return std::string{"First part "} += (condition ? "second" : "irrelevant");
    }

【讨论】:

  • 谢谢,我的项目使用 C++ 14,所以我想“第二”最好,但我认为这并不重要,因为这只是用于测试
  • @MichałP。你当然可以创建一个测试类,看看你的 C++14 编译器是如何处理它的。它可能会忽略复制,因为它允许这样做。
  • “在这种情况下允许复制省略” - 我知道这是关于“第一种”情况。 “你当然可以创建一个测试类,看看你的 C++14 编译器是如何处理它的”——这也是关于“第一”吗?您能否跟进“在 C++11 和 14 中,在这种情况下允许复制省略” - 这是因为 std::string impl 吗?我对复制省略不太熟悉,如果这个问题对你来说很愚蠢,我很抱歉:)
  • @MichałP。请将 c++14 标签添加到您的问题中
  • @MichałP。这与string 无关,所以如果您创建自己的类并在所有五个中使用调试打印实现the rule of five,您可以检查您的C++14 编译器如何在所有三个示例中处理它。我的猜测是在第一种情况下你会看到最少的复制/移动。
【解决方案2】:

@Ted_Lyngmo 已回答您的第一个问题

如果您真的关心性能(并且测量证明此功能是您的热点)std::string 在这种情况下有点太重了。它不允许所有编译时优化,例如constexpr

我建议使用std::string_view

#include <string_view>

constexpr std::string_view print(const bool condition) {
    if (condition){
        return "This is relevant info";
    } else {
        return "This is irrelevant info";
    }
}

int main() {
    std::string_view info = print(false);
    return info.size();
}

这个program 将被完全优化为

main:
        mov     eax, 23
        ret

如果你使用print(true),它会变成

main:
        mov     eax, 21
        ret

因此,如果您以后再使用该句子,编译器将对其进行最佳优化。

注意:如果您有 C++17 编译器,则只能使用 string_view

【讨论】:

  • 字符串连接的例子如何?抱歉,我没有明确提到它,但这与“条件”一起是我的“问题”:我需要根据传递给函数的参数创建一个字符串。
  • 你不能直接。 stackoverflow.com/questions/44636549/…请根据您的具体需求使用。
  • 如果您发现这确实是您的热点并且您只有 2*2 选项,您可以使用string_view 编码所有案例,如上所示。这会起作用,但不会增加可读性。
  • 如果您担心性能,请首先分析您的整个程序以确认担心是有道理的。如果您确实需要优化此代码,请在您的实际工作负载、您的实际平台和您的实际编译器上对它进行两种编码方式和配置文件。其他一切都是猜测。
  • 您应该使用sv 后缀:"This is relevant info"sv,以便string_view 构造函数可以使用长度信息
猜你喜欢
  • 2012-01-23
  • 1970-01-01
  • 1970-01-01
  • 2020-01-04
  • 2013-11-19
  • 1970-01-01
  • 2010-10-26
  • 2013-08-26
  • 1970-01-01
相关资源
最近更新 更多