Почему компилятор C++ не может исключить перемещение при перемещении POD в необязательный с RVO?

Рассмотрим следующий код (godbolt):

      #include <optional>
#include <array>

struct LargeType {
    std::array<int, 256> largeContents;
};

LargeType doSomething();

std::optional<LargeType> wrapIntoOptional(){
    return std::optional<LargeType> {doSomething()};
}

Как видите, есть функция, возвращающая большой POD, а затем функция, оборачивающая его в файл . Как видно из godbolt, компилятор создает здесь, поэтому он не может полностью исключить перемещение объекта. Почему это?

Если я правильно понимаю, то язык C++ позволяет исключить ход из-за правила «как если бы», так как видимых побочных эффектов у него нет. Так что кажется, что компилятор действительно не может этого избежать. Но почему?

Мое (вероятно, неправильное) понимание того, как компилятор может оптимизироватьout — передать ссылку на хранилище внутри необязательного(поскольку я предполагаю, что такие большие объекты все равно передаются по скрытой ссылке). Сам необязательный уже лежал бы в стеке вызывающей стороныиз-за РВО. Как определение конструкторанаходится в заголовке, он доступен для компилятора, поэтому он должен иметь возможность встроить его, чтобы он мог передать это место хранения вв первую очередь. Так что же не так с моей интуицией?

Чтобы уточнить: я не утверждаю, что язык C++ требует, чтобы компилятор встроил это. Я просто подумал, что это будет разумная оптимизация, и, учитывая, что перенос вещей в необязательные параметры является обычной операцией, это будет оптимизация, реализованная в современных компиляторах.

1 ответ

Можете добавитьnoexceptисключить копию:

https://godbolt.org/z/rrGEfrdzc

Другие вопросы по тегам