Domanda

Does anybody know why this code crashes?

Code that crashes:

QList<int> lst;
const auto& tmp = QList<int>() << 1;
lst = tmp;

Code that works (tmp is not a reference):

QList<int> lst;
const auto tmp = QList<int>() << 1;
lst = tmp;

Compiler:

Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.5.0
Thread model: posix 

Crash message:

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 "$@"

This message appears when 'lst' destructor called.

Under VisualStudio 2012 this code works well.

È stato utile?

Soluzione

After thinking about this more, I finally noticed the glaring inconsistency.

QList<int> lst;
const auto& tmp = QList<int>() << 1;
lst = tmp;

Specifically, looking at this line:

const auto& tmp = QList<int>() << 1;

QList<int>() is a temporary. This temporary is being passed into QList<int>::operator<<(...), which is then returning it back as a reference. The problem here is the level of indirection; if you tried to store QList<int>() into a const-reference, it should live until the const-reference fell out of scope. But that reference was instead passed to an operator as this, and is lost by the end of the statement.

Why this works in Visual Studio and not GCC is questionable. A quick Google for answers turns up at least one interesting result where it points to the following clauses in the standard:

If the initializer expression is an rvalue, with T2 a class type, and “cv1 T1″ is reference-compatible with “cv2 T2,” the reference is bound in one of the following ways (the choice is implementation defined):

The reference is bound to the object represented by the rvalue or to a subobject with that object

A temporary of type “cv1 T2″ is created, and a constructor is called to copy the entire rvalue object into the temporary. This reference is bound to the temporary or to a subobject with the temporary.

So, it looks like Visual Studio is taking the second approach, which happens to make a difference in this edge case, since the value will be copied in the statement anyways. It really does put into question the usefulness of a const-reference, though.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top