Кто-нибудь знает, почему этот код падает?
Код, который вылетает:
QList<int> lst;
const auto& tmp = QList<int>() << 1;
lst = tmp;
Код, который работает (tmp не является ссылкой):
QList<int> lst;
const auto tmp = QList<int>() << 1;
lst = tmp;
Составитель:
Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix
Аварийное сообщение:
qt_test(76726,0x7fff76257180) malloc: *** error for object 0x101208b60: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
qt_test: line 43: 76726 Abort trap: 6 $DBG_TEST "$@"
Это сообщение появляется, когда вызывается деструктор lst.
Под VisualStudio 2012 этот код работает хорошо.
Подумав об этом больше, я наконец-то заметил вопиющее несоответствие.
QList<int> lst;
const auto& tmp = QList<int>() << 1;
lst = tmp;
В частности, глядя на эту строку:
const auto& tmp = QList<int>() << 1;
QList<int>()
является временным. Этот временный переводится в QList<int>::operator<<(...)
, который затем возвращает его обратно в качестве ссылки. Проблема здесь — уровень косвенности; если вы пытались хранить QList<int>()
в const-ссылку, он должен жить до тех пор, пока const-ссылка не выйдет из области видимости. Но эта ссылка была передана оператору как this
и теряется к концу утверждения.
Почему это работает в Visual Studio, а не в GCC, сомнительно. Быстрый Google для ответов появляется по крайней мере один интересный результат где он указывает на следующие пункты в стандарте:
Если выражение инициализатора является r-значением, с T2 типом класса, и «cv1 T1» совместим со ссылками с «cv2 T2», ссылка связывается одним из следующих способов (выбор определяется реализацией):
Ссылка привязана к объекту, представленному значением r, или к подобъекту с этим объектом.
Создается временный объект типа «cv1 T2», и вызывается конструктор для копирования всего объекта rvalue во временный объект. Эта ссылка связана с временным или подобъектом с временным.
Таким образом, похоже, что Visual Studio использует второй подход, который в данном случае имеет значение, поскольку значение в любом случае будет скопировано в оператор. Это действительно ставит под сомнение полезность const-ссылки, хотя.
Других решений пока нет …