The range-based loop of C + + is a new feature of c++11, and it is convenient to replace the for loop usage of iterators to some extent. However, a range-based for loop has a hidden trap that can cause serious memory errors if you are not aware of it.
Examples Show
Look at the following code:
1#include <iostream>2#include <string>3 4 using namespacestd;5 6 structMyClass7 {8 stringText ="MyClass";9 Ten string&GetText () One { A returntext; - } - }; the - intMain () - { - for(Auto Ch:myclass (). Text) + { -cout <<ch; + } Acout <<Endl; at}
This code is very simple, the output is "MyClass". But if you modify line 18th slightly, change to the following:
for (Auto Ch:myclass (). GetText ()) { << ch; }
As a result, nothing is output and the program exits directly. To understand why this behavior occurs, first know how the scope-based for loop is defined.
Scope-based for loop definition
In the C++11 standard, it has the following format
attr (optional) for (range_declaration:range_expression) loop_statement
Where attr is optional, the range_declaration portion corresponds to the "Auto ch" in our code, and the range_expression portion corresponds to "MyClass ()." GetText () ", Loop_statement is" { cout << ch; }"
The standard specifies that the above loop expression should be equivalent to
{ && __range = range_expression; for (Auto __begin = begin_expr, __end = end_expr; __begin! = __end; + +__begin ) {= *__begin; Loop_statement }}
Where begin_expr and end_expr are determined by the type of range_expression.
It is worth noting that the __range type declared in the first line is "Auto &&", so if Range_expression is a temporary object with an rvalue, __range can prolong the lifetime of range_expression.
Problem analysis
After looking at the definition of the for loop for the given range, the reason for the problem in the previous example is clear.
In the original example, Range_expression is "MyClass (). Text", MyClass () is a temporary object, and the expression "MyClass ()" is the right value. Therefore, the expression "MyClass (). Text" is also an rvalue, "MyClass (). Text" This object is part of the temporary object. So, in the "auto && __range = range_expression;" Statement, Auto is deduced as "std::string". When initializing an rvalue reference as part of a temporary object, the lifetime of the entire temporary object can be extended, and the temporary object is destroyed when the reference is destroyed. So the For loop can execute normally.
But after the modification, range_expression is "MyClass (). GetText ()". Similarly, MyClass () is a temporary object, and the expression "MyClass ()" is the right-hand value. However, the return type of "GetText ()" is "string&", so the expression "MyClass (). GetText ()" is an lvalue. So, in "auto && __range = range_expression;" In this statement, Auto is deduced as "string &" and the statement is equivalent to "string & __range = range_expr ession; ". Although the "MyClass (). GetText ()" Object is part of a temporary object, it does not extend the lifetime of the temporary object when initializing a non-const lvalue reference, so the temporary object is destroyed at the end of the initialization statement MyClass (), __ Range becomes a wild reference, so a memory error may occur with subsequent loop statements.
Summarize
The range-based for loop is convenient, and can even traverse temporary objects, which are often used in everyday life. Note, however, that if you want to traverse a temporary object, the temporary object that needs to be traversed must be an rvalue expression, and notice that other temporary objects in the middle of the expression are destroyed before the loop starts, and only the last temporary object returned by the expression is "saved".
C + + trap based on range loop (range-based for Loop)