Является ли приведение временным с типом int в ссылочный сейф? - PullRequest
0 голосов
/ 17 февраля 2019

В следующей программе:

int Func()
{
    int a = { 10 };
    return a;
}
int main()
{  
    int& r = (int&)(const int&)Func();
    r = 5;        
}

r - ссылка на временный тип int.Но временные уничтожители немедленно уничтожаются, если они обычно не назначаются для ссылки.Задание выше не кажется нормальным.Безопасно ли использовать r в стандарте C ++?

1 Ответ

0 голосов
/ 18 февраля 2019

Введение: приведение в стиле C эквивалентно (C ++ 17 [expr.cast]):

int& r = const_cast<int&>( static_cast<const int&>(Func()) );

В подвыражении static_cast<const int&>(Func()) описывается поведениеC ++ 17 [expr.static.cast] / 4 (где T - это тип, который приводится к типу):

Если T является ссылочным типом, эффект тот жекак выполнение объявления и инициализации T t(e); для некоторой изобретенной временной переменной t (11.6), а затем использование временной переменной в результате преобразования

В этом случае T равно const int&, поэтому инициализация ссылки похожа на const int& t(Func());.

Теперь в этом коде есть две проблемы:

  • Тип временного
  • время жизни вовлеченного временного

Тип временного const int (C ++ 17 [dcl.init.ref] /5.2.1.2).Таким образом, ваш код вызывает неопределенное поведение, изменяя объект const. Ссылка на другой вопрос SO по этой теме

В остальной части этого ответа (обращаясь к проблеме на всю жизнь) я предполагаю, что вы измените r = 5 на какое-то утверждение, которое только читает r.


Поведение цепочки ссылок изменилось с применением CWG 1299 .Дефект был зарегистрирован в апреле 2011 года и устранен в марте 2017 года. Решение не появилось в C ++ 17 (N4659);оно появляется только в черновиках после C ++ 17.

Разрешение имеет статус DRWP, мое понимание этого заключается в том, что оно означает, что оно задним числом применяется к C ++ 17, но не к C ++ 14 (если кто-тохочет подтвердить или исправить это, что было бы замечательно).


В любом случае, это разрешение позволяет в некоторых случаях увеличивать срок службы по ссылочным цепочкам.Формулировка (N4762 class.tevent / 6):

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

  • [...]
  • a const_cast, static_cast, dynamic_cast или reinterpret_cast преобразование без определяемого пользователем преобразования операнда glvalue, который является одним из этих выражений, в glvalue, который относится к объекту, указанному операндомили к его полному объекту или подобъекту,

До CWG1299 этот параграф применялся только для инициализации ссылки из prvalue, но теперь он может применяться к случаям инициализации ссылки излюбая категория выражений, если обозначенный объект является временным объектом.

Обратите внимание, что способ временная материализация работает в C ++ 17, заключается в том, что prvalue преобразуется в xvalue, когда происходит материализация, и это xvalue является glvalue, на который ссылается жирный текст выше.

Теперь есть даже пример, подтверждающий это:

const int& b = static_cast<const int&>(0); // временное int имеет то же время жизни, что и b

В поведении компиляторов, показанных в другом удаленном ответе, должно применяться разрешение CWG1299.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...