How do Range-Based for loops handle temporary containers [duplicate] - c++

This question already has an answer here:
Does a C++11 range-based for loop condition get evaluated every cycle?
(1 answer)
Closed 8 years ago.
Assume this example:
vector<int> get_vector();
for(auto& v: get_vector())
{
...
}
Is get_vector() re-evaluated on each iteration? Or a temporary is stored and evaluated once?

get_vector() is evaluated once, and the result is stored in a temporary.
6.5.4/1 ...a range-based for statement is equivalent to
{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
In your example, range-init would be (get_vector()).

Related

C/C++: How do I compare execution times of two functions (or methods etc.)? [duplicate]

This question already has answers here:
How would you benchmark the performance of a function?
(1 answer)
Idiomatic way of performance evaluation?
(1 answer)
Loop with function call faster than an empty loop
(2 answers)
Simple for() loop benchmark takes the same time with any loop bound
(5 answers)
Closed 2 years ago.
I have two different C/C++ functions that do something. I think one may be a lot faster and I want to find out how much faster. So I do it in a loop a jillion times and time the loop.
Further, I think it might be so fast that the raw time just doing a loop to test it a jillion times could be taking, so I want to subtract out the cost of doing an empty loop.
And yet, code such as the following quite often reports the empty loop taking more time than a loop with a function, despite doing the loop 100 million times. I've taken to doing the empty loop twice but still it's sometimes slower.
Example code comparing two functions with two empty loops:
tp1 = chrono::high_resolution_clock::now();
for ( i = 0; i < iRepeats; i++ )
;
tp2 = chrono::high_resolution_clock::now();
for ( i = 0; i < iRepeats; i++ )
iLen = Function1();
tp3 = chrono::high_resolution_clock::now();
for ( i = 0; i < iRepeats; i++ )
iLen = Function2();
tp4 = chrono::high_resolution_clock::now();
for ( i = 0; i < iRepeats; i++ )
;
tp5 = chrono::high_resolution_clock::now();
double dDurEmpty1 = chrono::duration<double>( tp2 - tp1 ).count();
double dDurEmpty2 = chrono::duration<double>( tp5 - tp4 ).count();
double dDurEmpty = AKMin( dDurEmpty1, dDurEmpty2 );
double dDurA = chrono::duration<double>( tp3 - tp2 ).count();
double dDurB = chrono::duration<double>( tp4 - tp3 ).count();
printf( "Length: %7.4fx faster\n",
( dDurA - dDurEmpty ) / ( dDurB - dDurEmpty ) );
I'm not wedded to this general approach at all if there's any suggestion of different ways to do it.

What's the advantage of "If with a short statement"

What's the advantage of using an "If with a short statement" in go lang. ref: go tour
if v := math.Pow(x, n); v < lim {
return v
}
Instead of just write the statement before the if.
v := math.Pow(x, n)
if v < lim {
return v
}
if v := math.Pow(x, n); v < lim is interesting if you don't need 'v' outside of the scope of 'if'.
It is mentioned in "Effective Go"
Since if and switch accept an initialization statement, it's common to see one used to set up a local variable.
if err := file.Chmod(0664); err != nil {
log.Print(err)
return err
}
The second form allows for 'v' to be used after the if clause.
The true difference is in the scope where you need this variable: defining it within the if clause allows to keep the scope where that variable is used to a minimum.

Ranged for loop with literal list?

In C++11, is it possible to write the following
int ns[] = { 1, 5, 6, 2, 9 };
for (int n : ns) {
...
}
as something like this
for (int n : { 1, 5, 6, 2, 9 }) { // VC++11 rejects this form
...
}
tl;dr: Upgrade your compiler for great success.
Yeah, it's valid.
The definition of ranged-for in [C++11: 6.5.4/1] gives us two variants of syntax for this construct. One takes an expression on the right-hand-side of the :, and the other takes a braced-init-list.
Your braced-init-list deduces (through auto) to a std::initializer_list, which is handy because these things may be iterated over.
[..] for a range-based for statement of the form
for ( for-range-declaration : braced-init-list ) statement
let range-init be equivalent to the braced-init-list. In each case, a range-based for statement is equivalent to
{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
[..]
So, you are basically saying:
auto ns = { 1, 5, 6, 2, 9 };
for (int n : ns) {
// ...
}
(I haven't bothered with the universal reference here.)
which in turn is more-or-less equivalent to:
std::initializer_list<int> ns = { 1, 5, 6, 2, 9 };
for (int n : ns) {
// ...
}
Now, GCC 4.8 supports this but, since "Visual Studio 11" is in fact Visual Studio 2012, you'll need to upgrade in order to catch up: initialiser lists were not supported at all until Visual Studio 2013.
It is possible to use this construction with an initializer list. Simply it seems the MS VC++ you are using does not support it.
Here is an example
#include <iostream>
#include <initializer_list>
int main()
{
for (int n : { 1, 5, 6, 2, 9 }) std::cout << n << ' ';
std::cout << std::endl;
return 0;
}
You have to include header <initializer_list> because the initializer list in the for statement is converted to std::initializer_list<int>

Delete from STL list while using C++11 iterate syntax [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Erasing an element from a container while inside a range-based for loop
Similar to this, can you delete from an STL list while iterating over it using the new for( auto item : list ) syntax?
Here's a complete example (that crashes!)
#include <list>
using namespace std ;
int main()
{
list<int> li;
li.push_back( 4 ) ;
li.push_back( 5 ) ;
li.push_back( 6 ) ;
for( auto num : li )
{
if( num == 5 )
li.remove( num ) ;
else
printf( "%d\n", num ) ;
}
}
No, you can not. Your example crashes because you use li.remove(num) incorrectly and internal for-loop iterator is invalidated.
li.remove(num) should be used not in loop but as standalone statement. List member function remove iterates through all elements of a list and removes ones equal to value.
I would just enter your code into a compiler and see if it works.

PART 2 : Why do I need a Forward Iterator to implement my customized std::search

Don't think its necessary to read part one, but I'l include the link just incase:
why does std::search need forward iters
.....almost there with iterator catagories(I think) ..I looked around to find an easy all-in-1 table, that shows the functionality available from the various types of iterators ..couldn't find one so I'v tried to expand stroustrup's table to include things like: the ability to pass over a range more than once etc...let me know if I'v missed or misunderstood anything? ..or if there's a better table kicking about
*1++ must be (de)referenced between incrementions
*n++ can be incremented more than once without being (de)referenced
*n_save range can be passed over more than once and also saved/copied
------------------------------------------------------------------------------
- Iterator Operations and Categories
------------------------------------------------------------------------------
Category: output input forward bidirectional random-access
Abbreviation: Out In For Bi Ran
------------------------------------------------------------------------------
Read(*1++): =*p
Read(*n++): =*p =*p =*p
Read(*n_save): =*p =*p =*p
Write(*1++): *p=
Write(*n++): *p= *p= *p=
Write(*n_save): *p= *p= *p=
Access: -> -> -> ->[]
Iteration: ++ ++ ++ ++-- ++ -- + - += -=
Comparison: == != == != == != == != < > >= <=
------------------------------------------------------------------------------
Write(*n_save) ...wasn't sure if copying/saving an iter is read or write ..so I added it to both? ..Im guessing if you can read-pass a range more than once..you might also want to write-pass a range more than once?
I now understand why std::search needs forward iterators, but unsure why it needs 4 ..would 2 For & 2 In suffice?
while ( begin != end ) {
if( begin2 == end2 ) { return found ; }
}
..is it because end and end2 are refd more than once( every time the while loops)..?
template <class For, class In>
For search( For begin, In end, For begin2, In end2 )
{
For found ;
For pattern_begin = begin2 ; //refd
int flag = 0 ;
// search content for pattern
while ( begin != end ) { //refd
if ( *begin != *begin2 ) { //de-refd
begin2 = pattern_begin ; //store/copy
flag = 0 ;
begin++ ; //inc
} else {
if ( flag == 0 ) {
found = begin ;
flag = 1 ;
}
begin++ ;
begin2++ ;
}
if( begin2 == end2 ) { return found ; } //refd
}
return begin ;
}
I think you've pulled the "must be incremented between dereferencing" out of thin air.
Input and output operator implement those, so that they could be used by a function that doesn't expect them in particular, but essentially incrementing may well be a no-op with them.
That search function needs four iterators, because otherwise there would simply be no way to tell where either range ends. An iterator by itself does not (necessarily) know whether it is at the end of the range or not.
A range in SC++L is represented by a pair of iterators of the same type. Technically the algorithms could accept iterators of different type for a single range, but that would hardly have any practical use and just make the code more error-prone. As it is, at least one kind of errors can be detected at compile-time:
void foo(container& a, const container& b, const container& c) {
std::search(a.begin(), b.end(), c.begin(), c.end());
}
The error here is passing iterators into different containers for the first two arguments. But in this case this would be caught at compile-time, because fortunately a and b happen to have different constness, so a.begin() returns container::iterator and b.end() returns a different type container::const_iterator. If all four arguments were allowed to be of different types, then this error will lead to undefined behavior at runtime.