Для получения триального ключа
заполните форму ниже
Team License (базовая версия)
Enterprise License (расширенная версия)
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
GBP
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

** На сайте установлена reCAPTCHA и применяются
Политика конфиденциальности и Условия использования Google.
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте папку
Spam/Junk и нажмите на письме кнопку "Не спам".
Так Вы не пропустите ответы от нашей команды.

>
>
>
V828. Moving an object in a return stat…
Сообщения PVS-Studio
Диагностики общего назначения (General Analysis, C++)
Диагностики общего назначения (General Analysis, C#)
Диагностики общего назначения (General Analysis, Java)
Диагностика микро-оптимизаций (C++)
Диагностика 64-битных ошибок (Viva64, C++)
Cтандарт MISRA
Стандарт AUTOSAR
Дополнительная информация
Оглавление

V828. Moving an object in a return statement may prevent copy elision.

10 Авг 2020

Анализатор обнаружил ситуацию, когда локальная переменная, временный объект или параметр функции возвращаются из функции посредством вызова 'std::move'.

Рассмотрим пример:

struct T { .... };

T foo()
{
  T t;
  // ....
  return std::move(t);
}

На первый взгляд может показаться, что такой код более оптимизирован, так как первым будет гарантировано выбран конструктор перемещения, однако это не так. Использование 'std::move' в контексте возвращаемого выражения может запретить компилятору устранить вызов конструктора копирования / перемещения (copy elision, C++17) и применить RVO/NRVO для локальных объектов.

До появления семантики перемещения (C++11) компиляторы старались производить так называемую оптимизацию возвращаемого значения ([Named] Return Value Optimization) в обход вызова конструктора копирования, при которой возвращаемый объект создавался непосредственно в стеке вызывающей функции, а затем инициализировался вызванной функцией.

Такую оптимизацию компилятор может сделать лишь в том случае, если возвращаемый тип функции не является ссылкой, а операндом оператора 'return' является имя локальной не-'volatile' переменной, его тип должен совпадает с возвращаемым типом функции (игнорируя 'const' / 'volatile' квалификаторы).

Начиная с C++11, при возвращении из функции не-'volatile' локальной переменной компилятор попробует применить RVO/NRVO, затем конструктор перемещения, и лишь затем конструктор копирования. Поэтому, следующий код работает медленнее, чем ожидается:

struct T { .... };

T foo()
{
  T t;
  // ....
  return std::move(t); // <= V828, pessimization
}

В случае не-'volatile' формального параметра компилятор не может применить RVO/NRVO из-за технических ограничений, но попробует выбрать сначала конструктор перемещения, а затем конструктор копирования. Поэтому, следующий код содержит избыточный вызов функции 'std::move', который можно опустить:

struct T { .... };

T foo(T param)
{
  T t;
  // ....
  return std::move(param); // <= V828, redundant 'std::move' call
}

Также, начиная с C++17, если возвращаемое выражение имеет категорию prvalue (например, результат выполнения функции, которая возвращает не ссылку), то компилятор обязан оптимизировать код, удалив вызов конструктора копирования / перемещения (copy elision). Поэтому, следующий код работает медленнее, чем ожидается:

struct T { .... };

T bar();

T foo()
{
  return std::move(bar()); // <= V828, pessimization
}

Во всех случаях рекомендуется удалить вызов функции 'std::move' в целях оптимизации или устранения лишнего кода.

Дополнительная информация:

  • Стандарт С++20 (working draft N4860), пункт 11.10.5
  • C++ Core Guidelines F.48: Do not return std::move(local)
Этот сайт использует куки и другие технологии, чтобы предоставить вам более персонализированный опыт. Продолжая просмотр страниц нашего веб-сайта, вы принимаете условия использования этих файлов. Если вы не хотите, чтобы ваши данные обрабатывались, пожалуйста, покиньте данный сайт. Подробнее →
Принять