Reputation: 5091
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
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
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