tjgrant
tjgrant

Reputation: 438

In C++11 and later, is it still optimal to do an "empty" check before a "range for"?

I'm currently updating some older C++ code that I have that iterates over STL container types, and I'm finding a lot of code like this:

if (!edgeSet.empty())
{
  for(typename EdgeSet::const_iterator iter = edgeSet.begin(); iter != edgeSet.end(); iter++)
  {
    ...
  }
}

Which I am turning (successfully) into the equivalent:

if (!edgeSet.empty())
{
  for(auto& edge : edgeSet)
  {
    ...
  }
}

And I was wondering... is the "empty" check necessary for a "range for"? I would imagine it would be necessary in the older "iterator style" for loop to avoid a useless initialization and comparison / branch, but I'm curious if a "range for" automatically does an empty check or not before it even starts.

Further, if the optimization does happen, does it happen at all optimization levels (including no optimization: -O0 )?

Thanks in advance.

Upvotes: 0

Views: 2541

Answers (1)

P.W
P.W

Reputation: 26800

The empty() function checks if the container has no elements, i.e. whether begin() == end() and returns true if container is empty.

The range-based for loop produces code equivalent to the following

{
  auto && __range = range_expression ; 
  for (auto __begin = begin_expr, __end = end_expr; 
  __begin != __end; ++__begin) { 
    range_declaration = *__begin; 
    loop_statement 
  } 
} 

The controlling expression in the for loop is is __begin != __end. You can see the check in empty() and the check here are equivalent. So there is no need for an additional empty() check before using the range-based for loop.

Upvotes: 3

Related Questions