Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

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.

share|improve this question
2  
Are you aware of the std::accumulate function template from <numeric>? – Armen Tsirunyan Mar 19 at 20:46
@ArmenTsirunyan Thank you for your answer, I edited my post, explaining the reason behind this. – bash.d Mar 19 at 20:50
1  
I just check my copy of the book from 18.4: s = for_each(ld.begin(), ld.end(), s);. It seems you didn't follow the book correctly. – Jesse Good Mar 19 at 20:52
@JesseGood In the book he calls the method in a function, but this shouldn't make any difference, if I have a reference to a Container or the Container itself, should it? – bash.d Mar 19 at 20:54
@bash.d: No, it won't make a difference in the code. The difference is whether you properly handle the return from for_each. – Jesse Good Mar 19 at 20:56
show 4 more comments

1 Answer

up vote 5 down vote accepted

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.

share|improve this answer
Thank you, this works. It makes me wonder, though, as I copied this example from Stroustrup's The C++ Programming Language, chapter 18.4 – bash.d Mar 19 at 20:47
@bash.d: Sure you copied everything correctly? Maybe that's a mistake in the book, but I would tend to doubt it. Unless there is an Errata Corrige for it something (maybe on the website?) – Andy Prowl Mar 19 at 20:50
Yes, I am certain, only my variable's name is different. If you got the book (3rd edition), have a look at it. I haven't looked for errata, I expected this simple example to work out-of-the-box. – bash.d Mar 19 at 20:52
@bash.d: Unfortunately I do not have a copy of that book here, but it's possible that this is just a mistake. Good to know that it happens to Him as well apparently :) – Andy Prowl Mar 19 at 20:56
well, He is human, too :) As JesseGood stated in the comments: I don't have s = printed in my edition, so it couldn't work in the beginning! Thank you for your help. – bash.d Mar 19 at 21:01
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.