2

I tried finding some info about std::string Named Return Value Optimization (NVRO). I'm not even sure if this is applicable but I'm wondering which would be better from both readability and performance 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;
}

As in comments:

  1. Will the nvro be performed in "frist"?

  2. Is there a better (cleaner/performance) way of solving this problem?

My intention is to create a helper function that will concatenate correct string based on given param

Michał P.
  • 113
  • 6

2 Answers2

3
  1. In C++11 and 14, copy elision is permitted in that case. From C++17, return value optimization is mandatory (and no longer considered as copy elision).

  2. Not that I can see by looking at the three candidate functions @ godbolt but I don't do much assembler. This may look a little cleaner though:

    std::string fourth(const bool condition) {
        return std::string{"First part "} += (condition ? "second" : "irrelevant");
    }
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • Thanks, my project uses C++ 14 so I guess "second" would be best but I don't think it matters that much since this is just used for testing – Michał P. Jun 03 '19 at 11:33
  • @MichałP. You can of course create a test class and see how it's treated by your C++14 compiler. It may elide the copying since it's allowed to do that. – Ted Lyngmo Jun 03 '19 at 11:34
  • "copy elision is permitted in that case" - I understand this is about "first" case. "You can of course create a test class and see how it's treated by your C++14 compiler" - is this also about "first"? Can you please follow up on "In C++11 and 14, copy elision is permitted in that case" - is this because of std::string impl? I'm not well familiar with copy elision so sorry if this question is silly for you :) – Michał P. Jun 03 '19 at 11:39
  • @MichałP. Please add the c++14 tag to your question – Lightness Races in Orbit Jun 03 '19 at 11:44
  • @MichałP. It's not about `string` specifically so if you create your own class and implement [the rule of five](https://en.cppreference.com/w/cpp/language/rule_of_three#rule_of_five) with debug prints in all five, you can check how your C++14 compiler treats it in all three of your examples. My _guess_ is that you'll see the least amount of copying/moving being done in the first case. – Ted Lyngmo Jun 03 '19 at 11:44
  • @MichałP. Actually (maybe even if mandated by the standard?) I would recommend to actually _test_ it with a compiler, as the final outcome may be very different depending on various factors. For example on godbolt. – andreee Jun 03 '19 at 11:46
  • @andree and use a benchmarking framework, such as google benchmark to measure what speed-up can be achieved. – schorsch312 Jun 03 '19 at 12:15
2

Your first question has been ansered by @Ted_Lyngmo

If you are really concerend about performance (and measurements proof that this function is your hot spot) std::string is a bit too heavy in this case. It does not allow for all compile time optimizations, such as constexpr

I suggest to use 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();
}

This program will be entirely be optimized away to

main:
        mov     eax, 23
        ret

If you use print(true) it will change to

main:
        mov     eax, 21
        ret

Thus, also if you would use the sentence afterwards, it will be best optimized by the compiler.

Note: You can only use string_view, if you have a C++17 compiler.

schorsch312
  • 5,553
  • 5
  • 28
  • 57
  • 1
    How would you example look like with string concatenation? Sorry I didn't mention it explicitly but this along with "condition" is my "problem" : I need to create a string based on param passed to the funcion. – Michał P. Jun 03 '19 at 11:43
  • You can't directly. https://stackoverflow.com/questions/44636549/why-is-there-no-support-for-concatenating-stdstring-and-stdstring-view Please give use the concrete need you have. – schorsch312 Jun 03 '19 at 11:46
  • If you find that this really is your hot spot and you only have 2*2 options, you can code all cases with `string_view` as shown above. This will work, but not increase the readability. – schorsch312 Jun 03 '19 at 12:13
  • If you're worried about performance, first profile your whole program to confirm the worry is justified. If you really do need to optimize this code, then code it both ways and profile under your real workload, on your actual platform and with your actual compiler. Anything else is speculation. – Useless Jun 03 '19 at 12:39
  • you should use the `sv` suffix: `"This is relevant info"sv` so the length information is available to the `string_view` constructor – phuclv Sep 23 '20 at 05:03