До этого момента я исходил из предположения, что временный объект уничтожается в конце полного выражения , содержащего его.Недавно я наткнулся на раздел [class.teven] / 5 спецификации, в котором говорится об исключениях, которые возникают, когда временный объект назначается ссылке.По большей части это, кажется, всегда продлевает срок службы временной переменной, за исключением одного особого случая в [class.teven] / 5 :
- Временная привязка к ссылочному члену в ctor-initializer конструктора (12.6.2) сохраняется до выхода из конструктора.
- Временная привязка к ссылочному параметру в вызове функции (5.2.2)сохраняется до завершения полного выражения, содержащего вызов.
Если я читаю это, это указывает на то, что срок службы такого объекта может быть короче, чем full-выражение , если конструктор ссылается на него.
Пример:
struct A
{
A(int);
~A();
};
struct B
{
B(const A& a)
: memberRef(a)
{ }
~B();
const A& memberRef;
};
// Just a few operators to use in my full expression
int operator+(const A&, const A&);
int operator+(const A&, const B&);
void testCase()
{
int case1 = A(1) + A(2);
int case2 = A(3) + B(A(4));
}
Я дал каждому конструктору A
свой аргумент, чтобы было легко обращаться к временным переменнымсоздается как A1 , A2 , A3 и BA4 .
В случае 1, A1 и A2 создаются в любом порядке, затем происходит сложение.Продолжительность жизни A1 и A2 регулируется правилами для ссылок на параметры для вызова функции.Они распространяются на полное выражение, содержащее оператор сложения.
Деструкторы должны вызываться в обратном порядке, также в [class.teven] / 5:
Если время жизнииз двух или более временных объектов, ссылки на которые связаны, заканчиваются в одной и той же точке, эти временные объекты уничтожаются в этой точке в обратном порядке завершения их построения.
Так что это говорит мне о том, что деструкторыэти объекты должны быть вызваны в A1 , A2 или A2 , A1 , в зависимости от порядка, который компилятор выбрал для созданияобъекты.Пока все хорошо.
Проблемным делом для меня является case2.Если я прочитал это правильно, потому что A4 привязан к ссылке, переданной в B::B(const A&)
, его срок жизни теперь заканчивается в конце этого конструктора, , а не в конце выражения .
Это наводит на мысль, что деструкторы могут называться A4 , A3 , BA4 или A4 , BA4 , A3 .Однако деструктор для A4 всегда должен стоять первым, потому что он возникает в конце конструктора для BA4 , а не в конце полного выражения.
Предполагается, что деструкторы не могут быть вызваны в следующем порядке: A3 , BA4 , A4 , поскольку потребности в продолжительности жизни A4 быть сокращенным.
Правильно ли я читаю спецификацию? Если да, то в чем смысл этого правила?Мне кажется более естественным сделать временные переходы, передаваемые конструкторам, живыми, пока временные переходы переходят к вызовам функций, но похоже, что разработчики спецификаций предприняли усилия, чтобы создать правила иначе.