Pregunta

I am having trouble using function-objects in Visual Studio 2012.

I created a simple std::vector, added the ints 0-9 and wanted to create the sum of it using a function object. My class definition (inline):

template <class T>
class Sum {
private:
    T val;
public:
    Sum (T i = 0) : val(i) {
    }

    void operator()(T x) { 
        val += x; 
    }

    T result() const { 
        return val; 
    }

    ~Sum() {
        std::cout << "Invoked destructor! val: " << val << " for this: " << this << std::endl;
    }
};

My main function:

int main(int argc, char *argv[]){

    Sum<int> s;

    int contents[] = {1,2,3,4,5,6,7,8,9};

    std::vector<int> vec = std::vector<int>(contents, contents + 9);

    std::for_each(vec.begin(), vec.end(), s);

    std::cout << "Sum of all numbers: " << s.result() << std::endl;

    return 0;
}

Using the output from the destructor, I'll get:

Invoked destructor! val: 45 for this: 003BFDA4
Invoked destructor! val: 45 for this: 003BFDE0
Sum of all numbers: 0
Invoked destructor! val: 0 for this: 003BFEFC

Is this a bug from VS? Running through it using the debugger, the items are summed up to 45 but immediately afterwards the destructor is called. What am I doing wrong?

EDIT:

This is an example from Stroustrup's The C++ Programming Language, chapter 18.4. I just wondered it didn't work, as I copied it exactly.

¿Fue útil?

Solución

The problem is that std::for_each accepts your functor argument by value. This means it works on a copy of your original object. The good news is that it also returns that copy which holds the modified state. This should do the trick:

Sum<int> s1 = std::for_each(vec.begin(), vec.end(), s);
std::cout << "Sum of all numbers: " << s1.result() << std::endl;

Alternatively, you could let the val in your functor be a reference to some variable:

template <class T>
class Sum {
private:
    T& val;
public:
    Sum (T& i) : val(i) {
    }
// ...

Now, this should work:

int i = 0;
Sum<int> s(i);
std::for_each(vec.begin(), vec.end(), s);
std::cout << "Sum of all numbers: " << s1.result() << std::endl;

But you will have to take care of making sure that the lifetime of i is sufficiently extended not to make Sum<T>::val a dangling reference.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top