Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Range-based for loops in C++11 segfault, but not with regular for loop [closed]

//fills my vector with pointers.
//(some are pointing places, others are set to nullptr  
vector<Tree_NodeT*> xml_trees {Build_Tree_List(program_options->Get_Files())};

//time to print them
for (auto tree = xml_trees.begin(); tree != xml_trees.end(); ++tree){
    if (*tree){
        (*tree)->Print(std::cout,4);
    }
}
//this worked! No Segfaults!

//time to print them again
for (auto tree : xml_trees){
    if (tree){
        tree->Print(std::cout,4);
    }
}
//Crash! Segfault.

Why is the second loop segfaulting, while the first loop is not?

like image 234
Trevor Hickey Avatar asked Sep 20 '12 14:09

Trevor Hickey


2 Answers

EDIT:
I am a liar.
Tree_NodeT pointers were being created, but not initialized to nullptr somewhere in the Build_Tree_List function. Thus, I got a vector back where some of the pointers were pointing to valid memory, and others were just newly constructed pointers not set to null or given any address. It is still interesting that the first loop was able to handle this without crashing, while the second one segfaulted.

like image 142
Trevor Hickey Avatar answered Nov 01 '22 02:11

Trevor Hickey


Your range for loop is equivalent to:

for (auto it = xml_trees.begin(); it != xml_trees.end(); ++it) {
    auto tree = *it;
    if (tree){
        (tree)->Print(std::cout,4);
    }
}

The difference is that the range for loop is copy-constructing the dereferenced iterator. To get similar behaviour to your traditional for loop, use auto &:

for (auto &tree: xml_trees){
    if (tree){
        tree->Print(std::cout,4);
    }
}
like image 31
ecatmur Avatar answered Nov 01 '22 01:11

ecatmur