I'm working on a simple progress indicator class, and I have a question about using a std::ostream
object as a class member. The following example compiles and runs correctly on OS X and Linux.
#include <iostream>
#include <string>
struct ProgressIndicator {
public:
ProgressIndicator(unsigned int update_interval, std::string message,
std::ostream& outstream = std::cerr)
: update_interval(update_interval), message(message),
stream(outstream.rdbuf()), _counter(0), _interval(update_interval)
{
}
void increment(unsigned int by = 1)
{
_counter += by;
if(_counter >= _interval) {
stream << message << _counter << std::endl;
_interval += update_interval;
}
}
unsigned int get_count()
{
return _counter;
}
protected:
unsigned int update_interval;
std::string message;
std::ostream stream;
private:
unsigned long _counter;
unsigned long _interval;
};
int main()
{
ProgressIndicator p1(5, "progress <stdout> ", std::cout);
for(int i = 0; i < 15; i++) {
p1.increment();
}
ProgressIndicator p2(5, "progress <stderr> ", std::cerr);
for(int i = 0; i < 15; i++) {
p2.increment();
}
return 0;
}
I understand that std::ostream
objects cannot be copied, and must be passed by reference. But I don't understand why initializing with stream(outstream)
doesn't work, and why I had to resort to the rdbuf()
hack. Is there no "better", more idiomatic way to do this?
You are still copying the std::ostream
. Even though the constructor isn't copying the parameter, it still needs to copy the object into ProgressIndicator::stream
somehow.
One way to solve your problem would be to store a reference to the stream, though this only works if you know the stream object will outlast your class instance:
struct ProgressIndicator {
ProgressIndicator(std::ostream& outstream = std::cerr /* ... */)
: stream(outstream) /* ... */ {}
// ...
protected:
std::ostream& stream;
// ...
};