tags:

views:

161

answers:

10

I have an assignment that is the following:

For a given integer array, find the sum of its elements and print out the final result, but to get the sum, you need to execute the function for_each() in STL only once (without a loop).

As of now this is my code:

void myFunction (int i) {
cout << " " << i << " " <<  endl;
} 


int main() {

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

vector<int> v(array[0], array[10]);

for_each( v.begin(), v.end(), myFunction);

return 0;
}

But for some reason the output shows up as 4198853, at first I thought it was a memory address but I figured out that was wrong. Any idea's as to what I might be doing wrong?

+1  A: 

The array has 10 elements so 10 is not a valid array index.

vector<int> v(array[0], array[10]);
                              ^^

What you want is:

vector<int> v(array, array + sizeof(array) / sizeof(int) );
codaddict
+1  A: 

array has indexes 0..9, so array[9] = 10

if array[10] doesnt throw an error it will contain erroneous data, causing this problem.

John Boker
+9  A: 
vector<int> v(array[0], array[10]);

This doesn't do what you want. array[0] is the first value (1). array[10] is in invalid access past the end of your array. To pass pointers to the vector constructor, you want:

vector<int> v(array, array+10);
aschepler
beat me to it! :)
Nim
A: 

You need to take the address of array[0] and array[sizeof(array) / sizeof(*array)]. Vector constructor takes iterator types (i.e. pointers in this context), it can't magically determine the value of array[1] from the value of array[0].

DeadMG
+2  A: 

In this line:

vector<int> v(array[0], array[10]);

You've indexed out of bounds of your array. This causes undefined behavior.

Also, the constructor for vector you used doesn't do what you think. You've used:

vector(initial value, count);
JoshD
+1 for pointing out the overload that OP actually got by mistake
Steve Townsend
+2  A: 

why not just:

for_each( array, array+10, myFunction);

I'm quite sure that int* can be used as iterator

EDIT: just checked this, it can indeed

davka
As for "why not...", the answer is: "because `for_each` is the wrong tool for the job -- he should probably be using `std::copy`. Good uses for `std::for_each` are almost amazingly rare.
Jerry Coffin
Because it doesn't print out the sum of values in the array.
Noah Roberts
@Jerry: You probably mean std::accumulate, not std::copy
Nemanja Trifunovic
@Nemanja: Yes and no -- for the assigned task, `std::accumulate` is the right tool. For what he's trying to do right now, `std::copy` is the right tool. `std::for_each` isn't much good for either one though.
Jerry Coffin
@Jerry and @Nemanja: Except this is a homework assignment which appears to be about understanding and using STL algorithms, and explicitly says the student should use `for_each`. Sure, given the choice, I'd use `copy` with `ostream_iterator` for printing and `accumulate` for adding, but it's not hard to use `for_each` for either to get familiar with it.
aschepler
@aschepler: The first point to understanding and using algorithms is to pick the right one for the job. Forcing `for_each` into this job is outright abuse.
Jerry Coffin
It's easy if you use a variable with static storage duration. "Foul!" you immediately cry. Yeah, yeah, there are reasons not to use those things in many contexts. But none of those reasons really apply to an introductory C++ course homework assignment (as long as the course also points out somewhere those reasons). And really, global variables, static data members, and function static variables are legal in C++ for a reason and are sometimes okay.
aschepler
@aschepler - in addition to what Jerry's said, in my experience most instructors don't actually know things like std::for_each is not only free to make copies of it's input but normally does. In fact, unless I'm mistaken the signature of for_each takes its function parameter by value, not reference. The assignment is just plain wrong.
Noah Roberts
@aschepler - oh boy. Learning how to do things wrong only results in later having to UNLEARN the techniques you've been using. Teachers should be teaching how to do it right, not how to do it wrong and hoping that later they somehow figure out that they've been taught wrong.
Noah Roberts
@Jerry: "The first point to understanding and using algorithms" ... is to know what each one is capable of doing, surely? I absolutely agree that it would be best to illustrate `for_each` with an example that *wouldn't* be trivial using another algorithm, but I don't think there's really a whole lot wrong in principle with saying: "here's for_each. Here's some code using for_each. Now here's a better way to write that code, using a more appropriate algorithm, accumulate". Where in that process you set exercises, I don't really know, not being a teacher of C++.
Steve Jessop
@Steve: I'd start with what each is *intended* to do, not everything you might be able to get it to do. I do think it's wrong to start by using it for a task for which something else is far more suitable. You may not teach formal classes, but you *are* most definitely a teacher of C++ (and generally a pretty good one, IMO).
Jerry Coffin
@Jerry: OK, well, I don't know not being someone who sets C++ exercises, then :-) I don't really get what `for_each` is *supposed* to do for most people. Like you say, good uses are rare, because its use is so clumsy that prior to C++0x (and lambdas) you're better off writing a loop unless you're writing in a functional style. With C++0x, you're better off writing a range-based for statement much of the time. Obviously it's needed even if barely used, but personally if teaching I'd want to demonstrate it as the most basic possible loop algorithm and get on to something more interesting.
Steve Jessop
A: 

You're not constructing the vector right. The constructor that takes two integers is

vector(size_type _Count, const Type& _Val);

So _Count is 1 and _Value is an undefined value past the end of the array.

Seva Alekseyev
+4  A: 

Well, there's a couple problems beyond what people have said so far. One is your fault and the other is, in my opinion, a problem with the assignment.

You're printing out the elements, not the sum. The assignment asks for the sum so...you're doing it wrong. You need some call X that sums up all the values and sticks that into a variable for later printing.

The other problem is that std::for_each is not the appropriate algorithm for this task. In fact, it's so much not the appropriate algorithm that it's not even guaranteed to work without a lot of funky hacks to make all copies of the functor you pass in to for_each share the same counter. Maybe this is what your teacher wants you to figure out how to do, but I have a feeling (having experienced the common ability of programming instructors) that he/she doesn't actually know that they're teaching you wrong. The main gist of the problem is that implementations of std::for_each are free to make any number of copies of the function object passed in to recursive or utility calls to produce the standard behavior of for_each.

The appropriate algorithm to use is std::accumulate. In any production code I'd refuse to write, or accept from another team member, use of std::for_each to produce sums. However, I'd probably respond to this situation with a fugly hack and comment mentioning that for_each is the wrong algorithm. Something like so:

struct fugly_functor
{
  int * summation_variable; // using a local copy will result in correct answer, or a completely wrong answer depending on implementation of for_each

  fugly_functor(int * c) : counter(c) {}
  void operator(int x) { *summation_variable += x; }
};
...
int my_sum;
std::for_each(array, array+ELEM_COUNT, fugly_functor(&my_sum));
std::cout << my_sum << std::endl;

Then I'd suggest my teacher familiarize himself with the complete set of standard C++ algorithms.

The correct way would look something like so:

int my_sum = std::accumulate(array, array+ELEM_COUNT, 0);
Noah Roberts
+1: I was starting to write almost the same thing (though you did miss my line about: "for_each can be made to work, but it's about like using a screwdriver to pound a square peg into a round hole.") `std::accumulate` is definitely the right tool for this job.
Jerry Coffin
@Noah, @Jerry: Interesting, so are you saying that `Function g = f; while (first !=last) { g(*first); ++first; }; return f;` is a valid implementation of `for_each`? Of course `for_each` can copy the function object, indeed it has to return a copy, but I always understood that the return would be a value resulting from the application to each iterand in turn . Certainly it's the explicit intention of the original STL that the function object can have state: that's the rationale for returning it. One example given is to count the number of items. Has the standard abandoned this?
Steve Jessop
FWIW, I think the following is defined to work: `struct Adder() { int i; Adder() : i(0) {} void operator()(int x) { i += x; }; int total = for_each(first, last, Adder()).i;`, although I concede that the actual definition of `for_each` in the standard is very terse, and perhaps arguably does fail to require this. std::accumulate is still better for the job, of course.
Steve Jessop
@Steve: Unfortunately, all it requires is that it return a copy of the input functor. Yes, it clearly *should* return a copy post-operations, but nothing requires it (and I believe at least one real implementation did the wrong thing, at least for a while).
Jerry Coffin
@Jerry: hmm, sounds like a defect in the standard, though, if the intention is clear but the text is too ambiguous to express it. Any idea whether that real implementation was discovered and "fixed" before or after C++03?
Steve Jessop
@Jerry: another question - if `for_each`, and presumably other algorithms, are allowed to return a copy of function arguments that's not constructed from the copy/copies on which `operator()` was invoked, then are they allowed to use `const` copies? Is it invalid to pass a unary predicate with a non-const `operator()`? If it's the settled view that `std::for_each` is "broken" in either of these senses, then I can quite happily write and use my own version that's specified better (the way SGI intended) :-)
Steve Jessop
@Jerry: I think this more or less settles it: http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-active.html#92. No such note was included as far as I can tell, but neither were the algorithm definitions changed. IMO `for_each` should not say "Applies `f` to...". In fact it might apply a different copy of `f` to each element, and return yet another copy. Referring to all of these different objects as `f` has a slightly surprising meaning which is understood to the authors, and available if you dig into their discussions, but apparently stated nowhere in the standard.
Steve Jessop
@Steve: For whatever reason, I don't believe the note was added to C++03. For C++0x, instead of adding a note, they made a subtle change in the behavior: `f` is now moved instead of being copied. Since you only ever have one copy of the state, all state changes get propagated and eventually returned to the caller.
Jerry Coffin
A: 

If you really want to compute the sum, std::accucumulate is what you want, not for_each

Nemanja Trifunovic
A: 

I know you were told to use for_each, but I would actually do this - perhaps an alternative for extra credit ;-)

#include <numeric>
using namespace std;

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

int sum = accumulate(array, array + (sizeof(array) / sizeof(int)), 0);

accumulate is expressly designed for summing the elements of an iterable range.

Steve Townsend