2013-11-20 3 views
1

Кто-нибудь знает, почему этот код сработает?Странный сбой Qt 4.8.4 QList под Apple LLVM

Код, который выходит из строя:

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 "[email protected]" 

Это сообщение появляется при вызове 'lst' деструктора.

В VisualStudio 2012 этот код работает хорошо.

ответ

2

Подумав об этом больше, я, наконец, заметил вопиющую несогласованность.

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-reference, он должен жить до тех пор, пока ссылка на const не выпадет из области видимости. Но эта ссылка вместо этого передавалась оператору как this и теряется к концу инструкции.

Почему это работает в Visual Studio, а не в GCC, вызывает сомнения. Быстрый Google для ответов получается, по крайней мере один interesting result где он указывает на следующие положения, в стандарте:

Если выражение инициализатора является Rvalue с Т2 типа класса, и «CV1 T1" является справочно совместим с «CV2 Т2» ссылка связывается в одном из следующих способов (выбор зависит от реализации):

ссылка привязан к объекту, представленному RValue или подобъекту с этим объектом

Создан временный тип «cv1 T2», и вызывается конструктор для копирования всего объекта rvalue во временный. Эта ссылка привязана к временному или к подобъекту с временным.

Таким образом, похоже, что Visual Studio использует второй подход, который имеет значение в этом случае, поскольку значение будет скопировано в инструкции в любом случае. Тем не менее, это действительно ставит под сомнение полезность const-ссылки.

+0

Да, я так и думал. Я попытался воспроизвести проблему, используя MyClass вместо QList <>. Я заметил, что компилятор делает копию MyClass перед назначением 'tmp'. Поскольку tmp является ссылкой на константу, она должна сохранять эту копию в живых. В настоящее время я предполагаю, что проблема заключается в QList <> и неявном совместном использовании Qt. Если вы уверены, что в моем коде есть неопределенное поведение, укажите мне описание в стандарте C++. – esmirnov

+0

На самом деле, я забыл об этой функции C++.Но моя точка зрения заключается в том, что вы сохраняете значение, возвращаемое 'QList :: operator << (...)', а не временное - независимо от того, являются ли они одинаковыми или нет. Невозможно, чтобы компилятор мог знать, что 'operator << (...)' возвращает временный, который вы передали. –

+0

Обновлен мой ответ, с тем, что я надеюсь дать более полную картину проблемы. Гораздо более интересный краевой случай, чем я изначально изобразил. –

Смежные вопросы