"Наиболее важная константа" с условным выражением?
Рассмотрим следующий код:
int foo(MyClass const* aPtr = 0) {
MyClass const& a = aPtr ? *aPtr : MyClass(); // Either bind to *aPtr, or to a default-constructed MyClass
...
return a.bar();
}
"самый важный const" , мы надеемся, используется здесь. Цель состоит в том, чтобы позволить пропускать null aPtr
(BTW, да, это должен быть аргумент указателя), и в этом случае временный объект MyClass
будет построен по умолчанию, а его время жизни расширено на const ссылка на него. Принимая во внимание, что если aPtr
не было null, ссылка привязывалась бы к его объекту с указателем без какой-либо (дорогой) конструкции копирования.
Два вопроса:
- Если
aPtr == 0
, a
гарантированно ссылается на действительный объект MyClass
до конца функции?
- Если
aPtr != 0
, будет a
связываться с ним, а не с каким-либо другим MyClass
?
На основе тестирования ответ на 1 почти наверняка "да". # 2 Я не так уверен в том, что (копия elision и т.д.)... возможно, что условное выражение закончит копирование временного MyClass
из *aPtr
и продление срока действия этого временного.
Ответы
Ответ 1
Ваше условное выражение является prvalue (потому что один из его операндов). Если выбран первый вариант условного оператора, он преобразуется во временный (который берет копию). Это временное ограничение привязано к ссылке, и применяется обычное продление срока службы.
Соответствующий стандарт [expr.cond]:
Если операнды имеют тип класса, результатом является временное значение prvalue для типа результата, которое инициализируется копированием либо из второго операнда, либо из третьего операнда в зависимости от значения первого операнда.
Ответ 2
Во-первых, да a
, как правило, ссылается на действительный объект MyClass
. Это происходит непосредственно из [class.temporary]/4-5:
Есть два контекста, в которых временные объекты уничтожаются в другой точке, чем конец fullexpression. Первый контекст - это когда конструктор по умолчанию называется [...]
Второй контекст - это когда привязка привязана к временному. Временное, на которое ссылается связанный или временный, являющийся полным объектом подобъекта, к которому привязана ссылка , сохраняется для времени жизни ссылки, за исключением:
- Временная привязка к ссылочному элементу в конструкторах ctor-initializer [...]
- Временная привязка к ссылочному параметру в вызове функции [...]
- Время жизни временной привязки к возвращаемому значению в функции return statement [...]
- Временная привязка к ссылке в new-initializer [...]
Ни одно из этих исключений не применяется.
Если aPtr
является допустимым указателем, то создается копия, потому что тип aPtr ? *aPtr : MyClass{}
- это просто MyClass
. Это временное ограничение привязано к a
, и его жизненный цикл также сохраняется по той же причине.
Ответ 3
Пример 1) См. ответ kerek выше
Около 2) В стандарте говорится об условном операторе:
5.16/4: Если второй и третий операнды являются значениями той же категории значений и имеют тот же тип, результат этого типа и значения (...).
5.16/5: В противном случае результатом будет prvalue. (...)
В соответствии с таксономией lvalues и rvalues в 3.10/1, *aPtr
является lvalue, MyClass()
является prvalue. Следовательно, результат должен быть prvalue, так что ссылка должна ссылаться на эту временную (потенциально создаваемую копию temp).
Изменить: Здесь онлайн-демонстрация, которая показывает, что ссылка на const ссылается к временному, а не к исходному объекту, на который указывает aPtr.