"Наиболее важная константа" с условным выражением?

Рассмотрим следующий код:

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.