Когда компилятор C ++ 11 заставит RVO и NRVO превзойти семантику перемещения и привязку константных ссылок?

Рассмотрим случай, когда из функций возвращаются "целые" объекты с включенной семантикой перемещения, как в случае с std :: basic_string :

std::wstring build_report() const
{
    std::wstring report;
    ...

    return report;
}

Могу ли я тогда реально ожидать, что «лучший» выбор, использовать ли возвращаемую строку с семантикой перемещения, как в

const std::wstring report(std::move(build_report()));

, или полагаться на (N) RVO для выполнения с

const std::wstring report(build_report());

, или даже связать константную ссылку с временным с помощью

const std::wstring& report(build_report());

What есть ли схема для детерминированного выбора этих параметров, если таковые имеются?

РЕДАКТИРОВАТЬ 1: Обратите внимание, что использование std :: wstring выше является всего лишь примером типа с включенной семантикой перемещения . Его также можно заменить на вашу random_large_structure . : -)

РЕДАКТИРОВАТЬ 2: Я проверил сгенерированную сборку при запуске сборки выпуска с оптимизацией скорости в VS 2010 из следующего:

std::wstring build_report(const std::wstring& title, const std::wstring& content)
{
    std::wstring report;
    report.append(title);
    report.append(content);

    return report;
}

const std::wstring title1(L"title1");
const std::wstring content1(L"content1");

const std::wstring title2(L"title2");
const std::wstring content2(L"content2");

const std::wstring title3(L"title3");
const std::wstring content3(L"content3");

int _tmain(int argc, _TCHAR* argv[])
{
    const std::wstring  report1(std::move(build_report(title1, content1)));
    const std::wstring  report2(build_report(title2, content2));
    const std::wstring& report3(build_report(title3, content3));

    ...

    return 0;
}

2 наиболее интересных результата:

  • Явный вызов std :: move для report1 , чтобы использовать конструктор перемещения утроил счетчик команд.
  • Как отметил Джеймс МакНеллис в его ответ ниже , report2 и report3 действительно генерирует идентичную сборку с в 3 раза меньшим количеством инструкций, чем явный вызов std :: move .

15
задан Community 23 May 2017 в 12:15
поделиться