Продление жизни временного по константной ссылке
C++
Я пытаюсь понять, как ссылки на const продлевают жизнь временных пользователей. Я запускаю код из фрагмента в одном из ответов на вопросы. Каковы различия между переменной указателя и ссылочной переменной в C++? и получил противоречивые результаты между VC11 и g++ 4.8. Я расширил фрагмент здесь:
#include <stdio.h>
struct scope_test
{
~scope_test() { printf("scope_test done!\n"); }
};
int main()
{
const scope_test& test = scope_test();
printf("in scope\n");
}
Ответчик получил результат:
in scope
scope_test done!
Я попробовал это в VC11 и получил это:
scope_test done!
in scope
scope_test done!
Я предположил, что результат VC11 был вызван отсутствием разрешения копирования, поэтому я попытался проверить, отключено ли разрешение копирования на g ++ с fno-elide-constructors
даст тот же результат, что и VC11. (Я не думаю, что разрешение на копирование может быть переключено в VC11.) Но g ++ дает результат ответчика независимо от установки флага.
Стандарт C++11, ISO/IEC 14882:2011(E), §12.2/4 и / 5 гласит:
Есть два контекста, в которых временные уничтожаются в другой точке, чем конец полного выражения...
Второй контекст, когда ссылка связана с временным. Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется в течение всего времени существования ссылки, за исключением:
...
Имеет ли результат VC11 какое-либо отношение к копированию? Это ошибка VC11?
Ответчик заявляет:
Временные значения, присвоенные ссылкам const, сохраняются до тех пор, пока ссылка на const не выходит из области
Список исключений из §12.2/5 не исключает non-const
ссылка. Чего мне не хватает в Стандарте?
Удаление const в VC11 дает тот же результат, что и VC11 с const. Удаление const в g ++ дает error: invalid initialization of non-const reference of type ‘scope_test&’ from an rvalue of type ‘scope_test’
, Почему есть разница?
РЕДАКТИРОВАТЬ:
Я добавил конструкторы копирования и перемещения и попытался:
#include <stdio.h>
struct scope_test
{
scope_test() { printf("regular ctor\n"); }
scope_test(const scope_test& src) { printf("copy ctor\n"); }
scope_test(scope_test&& src) { printf("move ctor\n"); }
~scope_test() { printf("scope_test done!\n"); }
};
int main()
{
const scope_test& test= scope_test();
printf("in scope\n");
}
Независимо от переключения разрешения копирования, g ++ дает:
regular ctor
in scope
scope_test done!
VC11 дает то же самое, даже если const
устранен. Если const
удаляется из g++, g++ по-прежнему дает error: invalid initialization of non-const reference of type ‘scope_test&’ from an rvalue of type ‘scope_test’
,
1 ответ
Оба поведения являются правильными, безусловно, в соответствии со стандартом C++03 (8.5.3 [dcl.init.ref] параграф 5):
В противном случае ссылка должна быть на энергонезависимый тип const (т. Е. Cv1 должен быть const). [Пример: ...]
Если выражение инициализатора является r-значением, с T2 типом класса, и "cv1 T1" совместим со ссылками с "cv2 T2", ссылка связывается одним из следующих способов (выбор определяется реализацией):
- Ссылка привязана к объекту, представленному значением r (см. 3.10) или к подобъекту в этом объекте.
- Создается временный объект типа "cv1 T2" [sic], и вызывается конструктор для копирования всего объекта rvalue во временный объект. Ссылка привязана к временному или подобъекту во временном.
Я думаю, что определение C++11 все еще позволяет делать копию, но формулировка не так явно позволяет копировать. В любом случае, VC++ не претендует на полную совместимость с C++11.