power_output
power_output

Reputation: 421

Passing const to a function with a non-const parameter

I am following the Accelerated C++ book but I am confused with the source code they provide. My confusion involves the functions double grade(double midterm, double final, const vector<double>& hw) and double median(vector<double> vec). It says in the comment that the grade function does not copy its argument because the median function does. Why is that so? From my understanding you can't pass const to non-const since that would require write-access.

Here's the code:

#include <algorithm>
#include <iomanip>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

using std::cin;
using std::cout;
using std::domain_error;
using std::endl;
using std::istream;
using std::ostream;
using std::setprecision;
using std::sort;
using std::streamsize;
using std::string;
using std::vector;

// compute the median of a `vector<double>'
// note that calling this function copies the entire argument `vector'
double median(vector<double> vec)
{
#ifdef _MSC_VER
    typedef std::vector<double>::size_type vec_sz;
#else
    typedef vector<double>::size_type vec_sz;
#endif

    vec_sz size = vec.size();
    if (size == 0)
        throw domain_error("median of an empty vector");

    sort(vec.begin(), vec.end());

    vec_sz mid = size/2;

    return size % 2 == 0 ? (vec[mid] + vec[mid-1]) / 2 : vec[mid];
}

// compute a student's overall grade from midterm and final exam grades and homework grade
double grade(double midterm, double final, double homework)
{
    return 0.2 * midterm + 0.4 * final + 0.4 * homework;
}

// compute a student's overall grade from midterm and final exam grades
// and vector of homework grades.
// this function does not copy its argument, because `median' does so for us.
double grade(double midterm, double final, const vector<double>& hw)
{
    if (hw.size() == 0)
        throw domain_error("student has done no homework");
    return grade(midterm, final, median(hw));
}

// read homework grades from an input stream into a `vector<double>'
istream& read_hw(istream& in, vector<double>& hw)
{
    if (in) {
        // get rid of previous contents
        hw.clear();

        // read homework grades
        double x;
        while (in >> x)
            hw.push_back(x);

        // clear the stream so that input will work for the next student
        in.clear();
    }
    return in;
}


int main()
{
    // ask for and read the student's name
    cout << "Please enter your first name: ";
    string name;
    cin >> name;
    cout << "Hello, " << name << "!" << endl;

    // ask for and read the midterm and final grades
    cout << "Please enter your midterm and final exam grades: ";
    double midterm, final;
    cin >> midterm >> final;

    // ask for the homework grades
    cout << "Enter all your homework grades, "
            "followed by end-of-file: ";

    vector<double> homework;

    // read the homework grades
    read_hw(cin, homework);

    // compute and generate the final grade, if possible
    try {
        double final_grade = grade(midterm, final, homework);
        streamsize prec = cout.precision();
        cout << "Your final grade is " << setprecision(3)
             << final_grade << setprecision(prec) << endl;
    } catch (domain_error) {
        cout << endl << "You must enter your grades.  "
            "Please try again." << endl;
        return 1;
    }

    return 0;
}

Upvotes: 1

Views: 2739

Answers (2)

Hatted Rooster
Hatted Rooster

Reputation: 36463

Why is that so? From my understanding you can't pass const to non-const since what would require write-access.

Yes and no, it is correct that you can't write to a const variable but that's not what's happening here.

return grade(midterm, final, median(hw));

The call here to median does the work for us. median expects a std::vector and the compiler passes it one under the hood. It copies over the vector referenced by the const & and passes that copy to median. Remember, the compiler only needs read access to copy, not write, which is exactly what hw gives us.

Upvotes: 2

SingerOfTheFall
SingerOfTheFall

Reputation: 29966

Take a look at this line:

return grade(midterm, final, median(hw));

hw here is a const reference to a vector, which is being passed to median. While it is true that you can't modify an object through a const reference, you can still make a copy of it through a const reference. So, since median requires to change the vector (by sorting it), it makes a copy for itself (the copy will be implicitly created under the hood) and sorts it instead.

Upvotes: 2

Related Questions