简体   繁体   中英

Problem with file loop and reading into map

The while loop I have while reading in from a file doesn't break. I'm not sure what the problem is. If you need any more information just ask.

Code:

#include <string>
#include <map>
#include <fstream>
#include <iostream>
#include <iterator>

using namespace std;

class Customer {
public:
    string name;
    string address;
    Customer() {}
};

class Purchase {
public:
    string product_name;
    double unit_price;
    int count;
    Purchase() {}
    Purchase(string pn, double up, int c) :product_name(pn), unit_price(up), count(c) {}
};

// Function Object for comparison in map container
struct Cmp_name {
    bool operator()(const Customer& first, const Customer& second)
    { return first.name < second.name; }
};

// ostream overloads
ostream& operator<<(ostream& out, const Customer& c)
{
    out << c.name << '\n'
        << c.address << '\n';
    return out;
}

ostream& operator<<(ostream& out, const Purchase& p)
{
    out << p.product_name << '\n'
        << p.unit_price << '\n'
        << p.count << '\n';
    return out;
}

istream& operator>>(istream& in, Customer& c)
{
    getline(in, c.name);
    getline(in, c.address);
    return in;
}

istream& operator>>(istream& in, Purchase& p)
{
    getline(in, p.product_name);
    in >> p.unit_price >> p.count;
    return in;
}

int main()
{
    cout << "Enter file to read orders from: \n";
    string file;
    cin >> file;
    ifstream is(file.c_str());
    if (!is) cerr << "File doesn't exist.\n";

    multimap<Customer, Purchase, Cmp_name> orders;

    while (!is.eof()) {
        Customer c;
        Purchase p;

        is >> c;
        is >> p;

        orders.insert(make_pair(c,p));
    }

    for (multimap<Customer, Purchase, Cmp_name>::iterator it = orders.begin(); it!=orders.end(); ++it)
        cout << it->first << it->second << "\n\n";

}

As for your Customer/Purchase ostream inserters, declare the second argument const& instead of non-const &. For example:

ostream& operator<<(ostream& out, Customer const& c)

That's necessary because the key in a map is immutable even if you're using a non-const iterator (modifying the key would invalidate whatever tree-sorting or hashing the map implementation uses.

It's best to check every istream extraction operation for success, and break out of the loop the first time one doesn't succeed. Your "is.eof()" isn't going to read any extra (eg whitespace) characters, so it may claim "!eof()" at the semantic end of file.

Something like:

for(;;) {
        Customer c;
        Purchase p;

        if (!getline(is, c.name)) break;
        if (!getline(is, c.address) break;
        if (!getline(is, p.product_name) break;
        if (!(is >> p.unit_price >> p.count)) break;

        orders.insert(make_pair(c,p));
}

Since those all return the original istream, it's the same as having a "if (!is) break;" after every attempted input.

You can also simplify things somewhat by defining extractors for Customer and Purchase, eg

istream& operator>>(istream &i,Customer &c)

A failure to read a Customer would let you break out (the istream will evaluate as false if an eof stops the read from succeeding).

Obviously you can make some of the failed-input points "ok to eof" and give a specific error in all the other cases.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM