С++
Я пытаюсь понять, как константные ссылки продлевают срок службы временных. Я запускаю код из фрагмента в один из ответов на вопрос В чем разница между переменной-указателем и переменной-ссылкой в 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++ дает результат ответчика независимо от установки флага.
Стандарт С++ 11, ISO/IEC 14882:2011(E), §12.2/4 и /5 гласит:
Есть два контекста, в которых временные объекты уничтожаются не в конце полного выражения...
Второй контекст — это когда ссылка привязана к временному объекту. Временный объект, к которому привязана ссылка, или временный объект, являющийся полным объектом подобъекта, к которому привязана ссылка, сохраняется в течение всего времени существования ссылки, за исключением:
...
Имеет ли результат VC11 какое-либо отношение к копированию? Это ошибка VC11?
Ответчик заявляет:
временные объекты, назначенные константным ссылкам, живут до тех пор, пока константная ссылка не выйдет из области видимости.
Список исключений из §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’
.
const
не имеет ничего общего с продлением срока службы. Подойдет любая ссылка. Просто неконстантные ссылки lvalue не могут быть привязаны к rvalue, поэтому их никогда нельзя использовать таким образом. - person Kerrek SB   schedule 11.10.2013const
может привести к созданию копии. Самый простой способ проверить, была ли создана копия, — настроить конструктор копирования. - person Dietmar Kühl   schedule 11.10.2013The const has nothing to do with the lifetime prolongation...It's just that non-const lvalue references can't bind to rvalues, so the can never be used that way.
Согласно ответу DietmarKühl:Otherwise, the reference shall be to a non-volatile const type...
, в формулировке Стандарта не говорится, что ссылка должна быть объявлена константной; в нем указано, что референт должен быть константным типом. Неконстантная форма компилируется в VC11. Я что-то упустил здесь? - person CodeBricks   schedule 12.10.2013T&&
, и это продлит срок службы. - person Kerrek SB   schedule 12.10.2013const T & x = foo()
сT foo();
. В этом случае вы определенно хотите иметь возможность копировать результат вызова функции в локальную область. Но когда у вас естьT const & x = T()
, объект, возможно, уже находится в локальной области видимости, поэтому я надеюсь, что копирование не требуется, хотя стандарт, похоже, все равно разрешает это (возможно, чтобы просто не создавать дополнительных правил о различиях). Просто мое мнение... - person Kerrek SB   schedule 12.10.2013scope_test& test= scope_test();
неправильно сформирован и, следовательно, является ошибкой VC11, поскольку он компилируется в VC11, но не в g++? В этом отношенииscope_test test = *const_cast<const scope_test* const>( &( (scope_test()) ) );
также компилируется в VC11, но не в g++; g++ указываетerror: taking address of temporary
- person CodeBricks   schedule 12.10.2013