Carneiro
Carneiro

Reputation: 3509

Why does c++ range based for loop calls destructor at every iteration?

I am using a range based for loop to read (and parse) a file using an iterator. My loop looks like this:

for (auto record : reader) {
    if (even)
        record.reverse_complement();
    cout << record.write();
    even = !even;
} 

I have added outputs to the constructor and destructors of the iterator and it looks like the destructor is beign called on the iterator returned by end() in every iteration of the for loop.

calling fq_iter FULL constructor 
calling fq_iter default constructor 
calling fq_iter destructor on 0
calling fq_iter destructor on 0
calling fq_iter destructor on 0
calling fq_iter destructor on 0
calling fq_iter destructor on 0
calling fq_iter destructor on 0
calling fq_iter destructor on 0
calling fq_reader destructor on 0

These are the classes I am using to parse and iterate over the file, any idea why the destructor is being called at every iteration? (other than that, it produces the correct output).

Upvotes: 2

Views: 1406

Answers (3)

chris73it
chris73it

Reputation: 21

I am not a C++ guru, but I can attests that I landed here because I had the same problem described by the poster, and after reading Neil Kirk's comment, the issue disappeared by adding an '&' after the 'auto' keyword:

#include <iostream>
#include <array>

class Foo
{   
     int foo;
public:
    Foo() :foo(0) { std::cout << "Foo()" << std::endl; }
    Foo(int foo_) :foo(foo_) { std::cout << "Foo(int)" << std::endl; }
    virtual ~Foo() { std::cout << "~Foo" << std::endl; }
    int getFoo() { return foo; }
};

int main()
{
    std::array<Foo, 10> mainFoo = {0,11,22,33,44,55,66,77,88,99};

    //No destructors are called in this loop:
    for (auto aiter = mainFoo.begin(); aiter != mainFoo.end(); aiter++)
    {
        std::cout << aiter->getFoo() << std::endl;
    }

    //Destructors are called in this loop without the '&' in 'auto&':
    for (auto& i : mainFoo)
    {
        std::cout << i.getFoo() << std::endl;
    }
}

Upvotes: 1

Neil Kirk
Neil Kirk

Reputation: 21803

You are making a local copy of record each time. Try auto&

Upvotes: 1

Ben Voigt
Ben Voigt

Reputation: 283733

According to section 6.5.4 of the C++ Standard, your compiler is not supposed to do that. Instead, it's supposed to cache the end iterator in an unnameable local.

Does your operator!= make a copy of the iterator (accidental pass-by-value)?

Upvotes: 5

Related Questions