Каково время жизни аргумента по умолчанию, временно связанного со ссылочным параметром?

Я думал, что ссылки только увеличивают время жизни временных ссылок на время жизни самой ссылки, но вывод следующего фрагмента кажется противоречивым:

#include <iostream>

struct X{ ~X(){ std::cout << "Goodbye, cruel world!\n"; } };

X const& f(X const& x = X()){
std::cout << "Inside f()\n";
return x;
}

void g(X const& x){
std::cout << "Inside g()\n";
}

int main(){
g(f());
}

Живой пример. Выход:

Inside f()
Inside g()
Goodbye, cruel world!

Так что, кажется, временный разрушен после g() называется … что дает?

11

Решение

Стандарт обрабатывает это в особом случае в §12.2 [class.temporary]:

p4 Существует два контекста, в которых временные объекты уничтожаются в другой точке, чем конец полного выражения. […]

p5 Второй контекст — это когда ссылка связана с временным. Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется в течение всего времени существования ссылки, за исключением:

  • Временная граница с опорным параметром в вызове функции (5.2.2) сохраняется до завершения полного выражения, содержащего вызов.

Стандарт также содержит удобную заметку о полных выражениях и оценке их подвыражений относительно параметров по умолчанию в §1.9 [intro.execution] p11:

[ Замечания: Оценка полного выражения может включать оценку подвыражений, которые не являются лексической частью полного выражения. Например, подвыражения, участвующие в оценке аргументы по умолчанию (8.3.6) считаются созданными в выражении, которое вызывает функцию, не выражение, которое определяет аргумент по умолчанию. —Конечная записка ]
15

Другие решения

Интересно, +1. (Я не имею в виду, чтобы конкурировать с вашим хорошим ответом здесь). Просто примечание для всех, кто заинтересован. Если вы хотите подобный эффект, но допускаете неконстантность, вы можете использовать семантику перемещения:

#include <iostream>

struct X{
~X(){ std::cout << "Goodbye, cruel world!\n"; }
X(X && x){  std::cout << "moved "; }
X(){}
};

X  f(X x = X()){
std::cout << "Inside f()\n";
return x;
}

void g(X x){
std::cout << "Inside g()\n";
}

int main(){
g(f());
}

дает

Inside f()
moved Inside g()
Goodbye, cruel world!
Goodbye, cruel world!
1

По вопросам рекламы [email protected]