Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using C++11 range-based for loop correctly in Qt

Tags:

According to this talk there is a certain pitfall when using C++11 range base for on Qt containers. Consider:

QList<MyStruct> list;  for(const MyStruct &item : list) {     //... } 

The pitfall, according to the talk, comes from the implicit sharing. Under the hood the ranged-based for gets the iterator from the container. But because the container is not const the iterator will be non-const and that is apparently enough for the container to detach.

When you control the lifetime of a container this is easy to fix, one just passes the const reference to the container to force it to use const_iterator and not to detach.

QList<MyStruct> list; const Qlist<MyStruct> &constList = list;  for(const MyStruct &item : constList) {     //... } 

However what about for example containers as return values.

QList<MyStruct> foo() { //... }  void main() {     for(const MyStruct &item : foo())     {     } } 

What does happen here? Is the container still copied? Intuitively I would say it is so to avoid that this might need to be done?

QList<MyStruct> foo() { //... }  main() {      for(const MyStruct &item : const_cast<const QList<MyStruct>>(foo()))     {     } } 

I am not sure. I know it is a bit more verbose but I need this because I use ranged based for loops heavily on huge containers a lot so the talk kind of struck the right string with me.

So far I use a helper function to convert the container to the const reference but if there is a shorter/easier way to achieve the same I would like to hear it.

like image 477
Resurrection Avatar asked Mar 05 '16 06:03

Resurrection


People also ask

Does C have range-based for loops?

Range-based for loop in C++ It executes a for loop over a range. Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container.

How do you iterate a Qstringlist?

To iterate over a list, you can either use index positions or QList's Java-style and STL-style iterator types: Indexing: for (int i = 0; i < fonts. size(); ++i) cout << fonts.at(i).

How does range-based for loop work in C++?

C++11 introduced the ranged for loop. This for loop is specifically used with collections such as arrays and vectors. Here, the ranged for loop iterates the array num from beginning to end. The int variable var stores the value of the array element in each iteration.


1 Answers

template<class T> std::remove_reference_t<T> const& as_const(T&&t){return t;} 

might help. An implicitly shared object returned an rvalue can implicitly detect write-shraring (and detatch) due to non-const iteration.

This gives you:

for(auto&&item : as_const(foo())) { } 

which lets you iterate in a const way (and pretty clearly).

If you need reference lifetime extension to work, have 2 overloads:

template<class T> T const as_const(T&&t){return std::forward<T>(t);} template<class T> T const& as_const(T&t){return t;} 

But iterating over const rvalues and caring about it is often a design error: they are throw away copies, why does it matter if you edit them? And if you behave very differently based off const qualification, that will bite you elsewhere.

like image 124
Yakk - Adam Nevraumont Avatar answered Sep 20 '22 00:09

Yakk - Adam Nevraumont