Стандарт C++: возврат по копии для инициализации ссылки без RVO: есть ли копия?

Давайте рассмотрим следующий пример:

struct big_type {};

// Return by copy
auto factory() { return big_type{}; }

void any_scope_or_function() {
    big_type&& lifetime_extended = factory();
}

По предположению, RVO запрещено или не присутствует вообще, и каким-либо образом, будет или может big_type() копироваться? Или ссылка будет напрямую связана с временным, построенным в return заявление?

Я хочу быть уверен big_type деструктор вызывается только один раз, когда any_scope_or_function заканчивается.

Я использую C++14, если между версиями стандарта изменилось поведение.

2 ответа

Решение

Предполагая, что нет RVO/ копия elison, то в

auto factory() { return big_type{}; }

big_type{} собирается создать временный big_type, Затем этот объект будет использоваться для копирования инициализации объекта, который возвращает функция. Это означает, что объект, который вы создаете в функции, будет построен и разрушен.

С

big_type&& lifetime_extended = factory();

ссылка на rvalue продлит время жизни возвращаемых функций, поэтому мы увидим в общем вызов конструктора по умолчанию, вызов конструктора копирования / перемещения и два вызова деструктора.

Теперь, если мы изменим

auto factory() { return big_type{}; }

в

big_type factory() { return {}; }

тогда мы больше не создаем объект на фабрике. возвращаемый объект напрямую инициализируется {} давая нам всего вызов конструктора по умолчанию и вызов деструктора

Или ссылка будет напрямую связана с временным построением внутри оператора return?

Нет не будет Это именно то, что (N)RVO о / для, и вы явно не хотите этого.

Тем не менее, то, что будет предпринято, это использовать конструктор перемещения вашего big_type, который технически не является копией. Это нарушает: " big_type деструктор вызывается только один раз, когда any_scope_or_function заканчивается, хотя, так как он будет вызываться дважды.

GCC / Clang имеет хороший переключатель компилятора: -fno-elide-constructors это отключает (N)RVO, который может быть использован для дальнейшего использования. А пока вот тест, в котором эта опция включена, показывающий двойной вызов деструктора.

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