This question contains some proposals for working around the problem, I would like to understand more in depth that exactly the problem is:
QList<QString> q;
for (QString &x: q) { .. }
- Is it so that unless the container is declared
const, Qt makes a copy of the list and then iterates over that copy? This is not among the best, but would be bearable if the list is small (say 10-20 QString's). - Is it performance only problem or it can be some deeper problem? Let's assume we do not add/remove elements while the loop is running.
- Is the modification of the value in the loop (assuming it is a reference) something that still works or it is fundamentally broken?
Copy-on-write (=Implicit sharing) concept
It is important to understand that copy-on-write (= implicit shared) classes externally behaves like "normal" classes that perform a deep copy of their data. They only postpone this (potentially) expensive copy operation as long as possible. A deep copy is made (=detaching), only if the following sequence occurs:
Your questions
Only if the container is shared (by another copy on write instance of this list), a copy of the list will be made (as a non-const member is invoked on the list object). Note that the C++ range loop is just a short hand for a normal iterator based for loop (see [1] for the exact equivalence which depends on the exactly used C++ version):
Note that the
beginmethod is a const member function if and only if the listqitself is declared const. If you would write it in full yourself, you should useconstBeginandconstEndinstead.So,
doesn't perform any copy, as list
qisn't implicitly shared with another instance.However,
does make a copy of the data.
This is mostly a performance issue. Only if the list contain some special type with a weird copy constructor/operator, this may be not the case, but this would probably indicate a bad design. In rare cases, you may also encounter the Implicit sharing iterator problem, by detaching (i.e. deep copy) a list when an iterator is still active.
Therefore, it is good practice to avoid unneeded copies in all circumstances by writing:
or
Modifications in the loop aren't broken and work as expected, i.e. they behave as if the
QListdoesn't use implicit sharing, but performs a deep copy during a copy constructor/operator. For example,qandq2are identical, all containing 10 times "TEST".q3is a different list, containing 10 empty (null) strings.Also check the Qt documentation itself about Implicit Sharing, which is used extensively by Qt. In modern C++, this performance optimization construct could be (partially) replaced by newly introduced move concept.
Improve understanding by inspecting source code
Every non-const function calls
detach, before actually modifying the data, f.ex. [2]:However,
detachonly effectively detaches/deep copy the data when the list is actually shared [3]:and
isSharedis implemented as follows [4]:i.e. more than 1 copy (= another copy except for the object itself) exists.