NRVO для C++ std::string

Я попытался найти некоторую информацию об оптимизации именованного возвращаемого значения (NVRO) std::string. Я даже не уверен, применимо ли это, но мне интересно, что было бы лучше как с точки зрения читабельности, так и с точки зрения производительности.

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;
}

Как в комментариях:

  1. Будет ли нвро исполняться во "фристе"?

  2. Есть ли лучший (более чистый/производительный) способ решения этой проблемы?

Мое намерение состоит в том, чтобы создать вспомогательную функцию, которая будет объединять правильную строку на основе заданного параметра.


person Michał P.    schedule 03.06.2019    source источник
comment
1. Компилятор может использовать RVO в этом месте.   -  person user6556709    schedule 03.06.2019
comment
@MichalP Этот вопрос по-прежнему указан как без ответа. Разве ни один из предложенных ответов не помогает?   -  person Ted Lyngmo    schedule 12.06.2019


Ответы (2)


  1. В C++ 11 и 14 в этом случае разрешено исключение копирования. Начиная с C++17, оптимизация возвращаемого значения является обязательной (и больше не рассматривается как исключение копирования).

  2. Не то, чтобы я мог видеть, глядя на три функции-кандидата @ godbolt, но я не особо разбираюсь в ассемблере . Это может выглядеть немного чище:

    std::string fourth(const bool condition) {
        return std::string{"First part "} += (condition ? "second" : "irrelevant");
    }
person Ted Lyngmo    schedule 03.06.2019
comment
Спасибо, в моем проекте используется С++ 14, поэтому я думаю, что второй вариант будет лучшим, но я не думаю, что это имеет большое значение, поскольку он используется только для тестирования. - person Michał P.; 03.06.2019
comment
@МихалП. Конечно, вы можете создать тестовый класс и посмотреть, как он обрабатывается вашим компилятором C++14. Это может исключить копирование, поскольку это разрешено. - person Ted Lyngmo; 03.06.2019
comment
в этом случае разрешено удаление копии - я понимаю, что речь идет о первом случае. Вы, конечно, можете создать тестовый класс и посмотреть, как он обрабатывается вашим компилятором С++ 14 — это тоже самое первое? Не могли бы вы уточнить в С++ 11 и 14, в этом случае разрешено исключение копирования - это из-за std::string impl? Я не очень хорошо знаком с копированием, так что извините, если этот вопрос для вас глупый :) - person Michał P.; 03.06.2019
comment
@МихалП. Пожалуйста, добавьте тег С++ 14 к вашему вопросу - person Lightness Races in Orbit; 03.06.2019
comment
@МихалП. Это не касается string конкретно, поэтому, если вы создадите свой собственный класс и реализуете правило пяти с отладочными отпечатками во всех пяти, вы можете проверить, как ваш компилятор C++14 обрабатывает их во всех трех ваших примерах. Мое предполагаю, что в первом случае вы увидите наименьшее количество операций копирования/перемещения. - person Ted Lyngmo; 03.06.2019
comment
@МихалП. На самом деле (может быть, даже если это требуется стандартом?) Я бы порекомендовал на самом деле протестировать его с помощью компилятора, поскольку окончательный результат может сильно отличаться в зависимости от различных факторов. Например на богостреле. - person andreee; 03.06.2019
comment
@andree и используйте систему сравнительного анализа, например Google Benchmark, чтобы измерить, какое ускорение может быть достигнуто. - person schorsch312; 03.06.2019

На ваш первый вопрос ответил @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();
}

Эта программа будет полностью оптимизирована для

main:
        mov     eax, 23
        ret

Если вы используете print(true), он изменится на

main:
        mov     eax, 21
        ret

Таким образом, даже если вы впоследствии будете использовать это предложение, оно будет лучше всего оптимизировано компилятором.

Примечание. Вы можете использовать string_view, только если у вас есть C++17 компилятор.

person schorsch312    schedule 03.06.2019
comment
Как будет выглядеть ваш пример с конкатенацией строк? Извините, я не упомянул об этом явно, но это вместе с условием - моя проблема: мне нужно создать строку на основе параметра, переданного в функцию. - person Michał P.; 03.06.2019
comment
Вы не можете напрямую. stackoverflow.com/questions/44636549/ Пожалуйста, используйте конкретную потребность, которая у вас есть. - person schorsch312; 03.06.2019
comment
Если вы обнаружите, что это действительно ваша горячая точка, и у вас есть только 2 * 2 варианта, вы можете кодировать все случаи с помощью string_view, как показано выше. Это будет работать, но не повысит читабельность. - person schorsch312; 03.06.2019
comment
Если вы беспокоитесь о производительности, сначала профилируйте всю свою программу, чтобы убедиться, что беспокойство оправдано. Если вам действительно нужно оптимизировать этот код, кодируйте его обоими способами и профилируйте под вашу реальную рабочую нагрузку, на вашей реальной платформе и с вашим реальным компилятором. Все остальное - спекуляции. - person Useless; 03.06.2019
comment
вы должны использовать суффикс sv: "This is relevant info"sv чтобы информация о длине была доступна конструктору string_view - person phuclv; 23.09.2020