Why does the STL algorithm for yourself call twice the destructor of my functor?

advertisements

I was experimenting with the STL algorithms and more specific with the for_each function. I tried a simple use case for concatenating a vector of strings. Note that this is probably not a good and/or efficient code. Take a look at the boost::algorithm::join function, if you really want to concatenate a vector of strings.

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include "concatenator.h"

using namespace std;

int main(int argc, char **argv) {
     vector<string> list;
     list.push_back("hello");
     list.push_back("world");
     list.push_back("!!!");
     Concatenator concatenator;
     for_each(list.begin(), list.end(), concatenator);
     cout << "result = " << concatenator.getResult() << endl;
}

The concatenator class is implemented as a regular functor.

concatenator.h:

#include <string>

class Concatenator {
    public:
        Concatenator();

        virtual ~Concatenator();

        void operator()(const std::string s);

        std::string getResult();
    private:
        std::string fResult;
};

concatenator.cpp:

#include "concatenator.h"
#include <iostream>

Concatenator::Concatenator() :
        fResult("") {
    }

Concatenator::~Concatenator(){
    std::cout << "concatenator destructor called " << std::endl;
}

void Concatenator::operator()(const std::string s) {
    std::cout << "concat " << s << " to " << this->fResult << std::endl;
    this->fResult += " " + s;
}

std::string Concatenator::getResult() {
    return this->fResult;
}

If you compile and run this program, you get the following output:

concat hello to
concat world to hello
concat !!! to hello world
concatenator destructor called
concatenator destructor called
result =
concatenator destructor called

Can anybody explain why I can't extract the right result from the functor and why the destructor is called so many times.


std::for_each takes the functor object by value, not by reference. It then returns it by value. In other words, your original functor object never gets modified. So you need to do:

concatenator = for_each(list.begin(), list.end(), concatenator);

Incidentally, pass-by-value necessarily creates a copy of the object, hence the extra destructor calls.