75

I'm trying to use std::min_element and std::max_element to return the minimum and maximum elements in a vector of doubles. My compiler doesn't like how I'm currently trying to use them, and I don't understand the error message. I could of course write my own procedure to find the minimum and maximum, but I'd like to understand how to use the functions.

#include <vector>
#include <algorithm>

using namespace std;

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

    double cLower, cUpper;
    vector<double> C;

    // Code to insert values in C is not shown here

    cLower = min_element(C.begin(), C.end());
    cUpper = max_element(C.begin(), C.end());

    return 0;
}

Here is the compiler error:

../MIXD.cpp:84: error: cannot convert '__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >' to 'double' in assignment
../MIXD.cpp:85: error: cannot convert '__gnu_cxx::__normal_iterator<double*, std::vector<double, std::allocator<double> > >' to 'double' in assignment

What am I doing wrong?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
synaptik
  • 8,971
  • 16
  • 71
  • 98

3 Answers3

108

min_element and max_element return iterators, not values. So you need *min_element... and *max_element....

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • 25
    An iterator is a pointer in that it points to things. But it may or may not be an ordinary pointer. For example, if an iterator refers to an object in a list, incrementing it makes it point to the next object in the list. Incrementing an ordinary pointer only does that for collections like a vector that are guaranteed to store their contents in sequence memory addresses. – David Schwartz Apr 15 '12 at 01:51
  • 2
    in case the vector is empty `*max_element` raises error. Is there any solution to handle this issue? Right now I check if vector is empty or not and then use `*max_element` – Moj Dec 06 '13 at 15:22
  • I think that's the best solution. You need to handle the case specially anyway, because there's no sensible value that can be returned. – David Schwartz Dec 06 '13 at 18:09
  • 3
    @Moj: you can check the iterator against `C.end()`. – intelfx Jun 10 '14 at 15:50
57

As others have said, std::max_element() and std::min_element() return iterators, which need to be dereferenced to obtain the value.

The advantage of returning an iterator (rather than just the value) is that it allows you to determine the position of the (first) element in the container with the maximum (or minimum) value.

For example (using C++11 for brevity):

#include <vector>
#include <algorithm>
#include <iostream>

int main()
{
    std::vector<double> v {1.0, 2.0, 3.0, 4.0, 5.0, 1.0, 2.0, 3.0, 4.0, 5.0};

    auto biggest = std::max_element(std::begin(v), std::end(v));
    std::cout << "Max element is " << *biggest
        << " at position " << std::distance(std::begin(v), biggest) << std::endl;

    auto smallest = std::min_element(std::begin(v), std::end(v));
    std::cout << "min element is " << *smallest
        << " at position " << std::distance(std::begin(v), smallest) << std::endl;
}

This yields:

Max element is 5 at position 4
min element is 1 at position 0

Note:

Using std::minmax_element() as suggested in the comments above may be faster for large data sets, but may give slightly different results. The values for my example above would be the same, but the position of the "max" element would be 9 since...

If several elements are equivalent to the largest element, the iterator to the last such element is returned.

johnsyweb
  • 136,902
  • 23
  • 188
  • 247
26

min/max_element return the iterator to the min/max element, not the value of the min/max element. You have to dereference the iterator in order to get the value out and assign it to a double. That is:

cLower = *min_element(C.begin(), C.end());
Cornstalks
  • 37,137
  • 18
  • 79
  • 144