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

Рассмотрим случай, когда «целые» объекты с включенной семантикой перемещения возвращаются из функций, как при 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());

Какая схема существует для детерминистского выбора этих вариантов, если таковые имеются?

РЕДАКТИРОВАТЬ 1: Обратите внимание, что использование std::wstring выше - только пример типа с включенной семантикой перемещения. Точно так же можно обменять его на arbitrary_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.

Ответы [ 3 ]

13 голосов
/ 30 июня 2011

std::move(build_report()) совершенно не требуется: build_report() уже является выражением rvalue (это вызов функции, которая возвращает объект по значению), поэтому конструктор перемещения std::wstring будет использоваться, если он есть (он делает).

Кроме того, когда вы возвращаете локальную переменную, она перемещается, если она имеет тип, имеющий конструктор перемещения, поэтому копии не будут создаваться, точка.

Не должно быть функциональной разницы между объявлением report как объекта или как const-ссылки; в обоих случаях вы получите объект (либо именованный объект report, либо неназванный объект, к которому может быть привязана ссылка report).

4 голосов
/ 30 июня 2011

Я не уверен, что это стандартизировано (как говорит Николь, все оптимизации выполняются компилятором), но я слышал, как STL говорит об этом и (по крайней мере, в MSVC), происходит RVO до что-нибудь еще.Так что, если есть шанс применить RVO, это произойдет без каких-либо действий с вашей стороны.Во-вторых, когда вы возвращаете временное значение, вам не нужно писать std::move (я думаю, что на самом деле в стандарте), поскольку возвращаемое значение будет неявно рассматриваться как значение r.

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

3 голосов
/ 30 июня 2011

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

Нет ни одного, и никогда не будет.

Компиляторы не требуются для выполнения любых видов оптимизации. Единственное, что вы можете сделать наверняка, это скомпилировать некоторый код и посмотреть, что получится на другом конце.

Максимум, что вы в итоге получите, это общая эвристика, консенсус сообщества, когда люди говорят: «Для большинства компиляторов X, кажется, работает быстрее всего». Но это все. И это займет лет , так как компиляторы набирают скорость с C ++ 0x и реализации становятся зрелыми.

...