Apple LLVM下Qt 4.8.4 QList的奇怪崩溃

时间:2013-11-20 14:14:03

标签: c++ macos qt llvm-clang qlist

有人知道为什么这段代码会崩溃吗?

崩溃的代码:

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下,此代码运行良好。

1 个答案:

答案 0 :(得分: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-reference超出范围。但是该引用反而作为this传递给运算符,并在语句结束时丢失。

为什么这在Visual Studio中起作用而不是GCC是有问题的。一个快速谷歌的答案至少有一个interesting result,它指向标准中的以下条款:

  

如果初始化表达式是rvalue,T2是类类型,并且“cv1 T1”与“cv2 T2”引用兼容,则引用以下列方式之一绑定(选择是实现定义的):

     

引用绑定到rvalue表示的对象或带有该对象的子对象

     

创建一个类型为“cv1 T2”的临时表,并调用构造函数将整个右值对象复制到临时对象中。此引用绑定到临时或具有临时的子对象。

因此,看起来Visual Studio正在采用第二种方法,这恰好在这种边缘情况下有所不同,因为该值无论如何都将被复制到语句中。但它确实对const-reference的有用性提出了质疑。