leon
leon

Reputation: 5091

uninformative error using boost::iterator_adaptor

I am trying to wrap a istream with boost's progress_display using boost::iterator_adaptor. What I have written is

class ifstreamWithProgress: public boost::iterator_adaptor <
  ifstreamWithProgress,
  char*,
  boost::use_default,
    boost::forward_traversal_tag > {
public:
//  ifstreamWithProgress(const char* fname_) {}
  ifstreamWithProgress(): iter(std::istream_iterator<char>()), pd(0)
  {}

  ifstreamWithProgress(const std::string& fname_): fname(fname_), fsize(0), pd(fsize) {
    std::ifstream file(fname.c_str(), std::ios::binary);
    fsize = file.tellg();
    file.seekg(0, std::ios::end);
    fsize = file.tellg() -  fsize;
    file.seekg(0, std::ios::beg);
    iter = std::istream_iterator<char>(file);
    pd.restart(fsize);
  }

  ~ifstreamWithProgress() {
    while( ++pd < fsize);
  }

  const std::istream_iterator<char> getRawIstream() const {
    return iter;
  }

private:
  std::string fname;
  friend class boost::iterator_core_access;
  std::istream_iterator<char> iter;
  std::streampos fsize;
  progress_display pd;

  void increments() {
    iter++;
    ++pd;
  }

  bool equal(const ifstreamWithProgress& rhs) const {
    return this->iter == rhs.getRawIstream();
  }
};

This compiles. However when I started to do something like

  ifstreamWithProgress is("data.txt");
  ifstreamWithProgress eos;
  is != eos;

I get a compile time error saying that it is not copyable. This makes some sense because the display class is derived from boost::noncopyable. However what I do not get is where the copying occurs. Any pointers?

PS: the error message is

1>c:\users\leon.sit\documents\myprojects\c++\general_models\phoenixdsm\phx\fileProgressBarWrapper.hpp(58) : error C2248: 'boost::noncopyable_::noncopyable::noncopyable' : cannot access private member declared in class 'boost::noncopyable_::noncopyable'
1>        C:\Program Files\boost\boost_1_44\boost/noncopyable.hpp(27) : see declaration of 'boost::noncopyable_::noncopyable::noncopyable'
1>        C:\Program Files\boost\boost_1_44\boost/noncopyable.hpp(22) : see declaration of 'boost::noncopyable_::noncopyable'
1>        This diagnostic occurred in the compiler generated function 'ifstreamWithProgress::ifstreamWithProgress(const ifstreamWithProgress &)'

which does not point to anywhere in source. However it compiles after commenting the comparison line.

Upvotes: 3

Views: 342

Answers (2)

Yakov Galka
Yakov Galka

Reputation: 72529

Iterators are intended to be lightweight objects that can be copied. All the standard utilities that accept iterators get them as by value parameters. The inequality operator != defined by boost_adaptor is not an exception. Hence this:

is != eos;

Matches:

bool operator != (ifstreamWithProgress, ifstreamWithProgress);

(or one of the equivalents). This calls the copy constructor of your ifstreamWithProgress, which in turn can't be generated because one of your members is not copyable.

Upvotes: 1

facetus
facetus

Reputation: 1138

Copying doesn't have to occur anywhere to produce this error. It is a simple reflection of the fact that the compiler must generate a copy constructor. But to do it, it has to copy progress_display as well, which is impossible, since the copy constructor of the latter is private.

You can work around by declaring a pointer to the progress_display member and defining your own copy constructor and = operator. For example:

class ifstreamWithProgress: public boost::iterator_adaptor <
  ifstreamWithProgress,
  char*,
  boost::use_default,
    boost::forward_traversal_tag > {
public:
  ifstreamWithProgress() : pd(0) {
    pd = new progress_display(...);
  }

  ifstreamWithProgress::ifstreamWithProgress(const ifstreamWithProgress &r) : pd(0) {
    pd = new progress_display(...);
  }

  ~ifstreamWithProgress() {
    if (0 != pd) {
      delete pd;
    }
  }

  ifstreamWithProgress& operator= (const ifstreamWithProgress &r) {
    if (0 != pd) {
      delete pd;
    }
    pd = new progress_display(...);
    return *this;
  }

private:
  progress_display *pd;
};

Or you can use shared_ptr<progress_display>.

Upvotes: 1

Related Questions