简体   繁体   中英

Constructing a vector of custom type with istream_iterator

I want to write and read STL Vector of my class type to binary file, but don't understand what's wrong with istream_iterator.
Project rules disallow to use text files, same as third-party libraries like Boost.

This is Book.h:

class Book{
    public:
    Book(const std::vector<Book>& in_one_volumes,const std::string& title,
    const std::string& author,const int pagecount,const int price,const std::string& date);
    private:
    std::vector<Book> inOneVolumes;
    std::string title;
    std::string author;
    int pagecount;
    int price;
    std::string date;
};

This is write method:

void writeBook(std::vector<Book> books) {
    std::ofstream binOut("book.bin", std::ios::binary);
    std::copy(books.begin(), books.end(),
        std::ostream_iterator<Book>(binOut, "\n")); 
}

And i want to read like this:

std::vector<Book> readBooks() {
    std::vector<Book> toReturn;
    std::ifstream BinIn("book.bin", std::ios::binary);
    std::istream_iterator<Book> file_iter(BinIn);
    std::istream_iterator<Book> end_of_stream;
    std::copy(file_iter, end_of_stream, std::back_inserter(toReturn));
    return toReturn;    
}

Compiller says -- Book:no appropriate default constructor available.

std::istream_iterator<Book> uses operator>>(std::istream&, Book&) to read data into objects. Since this operator>> requires an existing Book object as parameter (to write the data into), the iterator has to construct one before it can dump the data from the stream into it, and for this it requires a default constructor.

Your Book class does not have one. The easiest solution to the problem would be to give it one.

In the event that this is not an option (eg, if Book as to guarantee invariants that a default constructor cannot provide), you could introduce an intermediate data transfer class that is default-constructible, can be filled with data via operator>> , and can be converted to Book . Sketch:

class TransferBook {
public:
  // To read data from stream
  friend std::istream &operator>>(std::istream &in, TransferBook &dest);

  // Conversion to Book. Use the non-default Book constructor here.
  operator Book() const {
    return Book(all the data);
  }

private:
  // all the data
};

...

std::vector<Book> books;
std::ifstream file;

// Note that books contains Books and the iterator reads TransferBooks.
// No Book is default-constructed, only TransferBooks are.
std::copy(std::istream_iterator<TransferBook>(file),
          std::istream_iterator<TransferBook>(),
          std::back_inserter(books));

To be sure, this approach is rather cumbersome and essentially duplicates code, and probably it is less hassle to give Book the default-constructor. However, if Book cannot be changed in this way, this is a possible workaround.

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