Стандарт 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, который может быть использован для дальнейшего использования. А пока вот тест, в котором эта опция включена, показывающий двойной вызов деструктора.