Output stream as class member
Solution 1
You've got two options here:
- Use references, or
- Use pointers
You can't use normal instances because ostream
is non-copyable.
Using references (direct reference to an already-instantiated ostream
)
class PVirtualMachine {
private:
std::ostream & output;
[...]
public:
PVirtualMachine(std::ostream &); // Reference must be initialized on construction.
[...]
};
Advantages:
- No pointer syntax.
- Should always refer to a valid instance of
std::ostream
, as long as the original variable is not deleted.
Disadvantages:
- The
PVirtualMachine
class must be constructed with the output reference in the initialization list, otherwise it will not compile. - Cannot change the reference once it has been initialized.
- Cannot work with move-assignment operators (i.e.
operator=(PVirtualMachine &&)
)
Using pointers (optional reference to object)
class PVirtualMachine {
private:
std::ostream * output;
[...]
public:
void setOutput(std::ostream *);
[...]
};
Advantages:
- Can be instantiated as a null pointer.
- Can be passed around easily.
- Can be updated to point to a new
std::ostream
instance. - Can be created internally or externally to the PVirtualMachine instance.
- Works with move-assignment operator.
Disadvantages:
- Pointer syntax.
- Must check for null references when accessing the ostream and/or in the constructor.
Solution 2
You can use a reference to a std::ostream
instead, this would support any kind of output stream, e.g. stdout, file, etc. This is fine as long as you only want to use one single stream, and the stream doesn't get destroyed:
class PVirtualMachine {
private:
std::ostream & output;
[...]
public:
PVirtualMachine(std::ostream & os = std::cout): output(os) { }
// void setOutput(std::ostream & os) { output = os; } // can't change the reference
[...]
};
If you want this class to share the stream (therefore keeping it alive for this class's lifetime), use a std::shared_ptr<std::ostream>
instead of a reference.
Comments
-
ducin over 1 year
I have a c++ library that provides an object with complicated logic. During data processing, this object outputs lots of things to std::cout (this is hardcoded now). I would like the processing output not to go to standard output but to a custm widget (some text displaying). I tried to create a
std::ostream
class member, set it with a parameter (std::cout for console application and some other ostream handled inside GUI application). But the compiler throws me following errors:[ 14%] Building CXX object src/core/CMakeFiles/PietCore.dir/pvirtualmachine.cpp.o /usr/include/c++/4.6/ostream: In constructor ‘PVirtualMachine::PVirtualMachine(QString)’: /usr/include/c++/4.6/ostream:363:7: error: ‘std::basic_ostream::basic_ostream() [with _CharT = char, _Traits = std::char_traits]’ is protected /home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp:33:50: error: within this context In file included from /usr/include/c++/4.6/ios:45:0, from /usr/include/c++/4.6/ostream:40, from /usr/include/c++/4.6/iterator:64, from /usr/include/qt4/QtCore/qlist.h:50, from /usr/include/qt4/QtCore/qvector.h:48, from /usr/include/qt4/QtGui/qpolygon.h:45, from /usr/include/qt4/QtGui/qmatrix.h:45, from /usr/include/qt4/QtGui/qtransform.h:44, from /usr/include/qt4/QtGui/qimage.h:45, from /usr/include/qt4/QtGui/QImage:1, from /home/tomasz/Development/C++/piet/src/core/pcodepointer.h:17, from /home/tomasz/Development/C++/piet/src/core/pblockmanager.h:9, from /home/tomasz/Development/C++/piet/src/core/pvirtualmachine.h:10, from /home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp:4: /usr/include/c++/4.6/bits/ios_base.h: In member function ‘std::basic_ios& std::basic_ios::operator=(const std::basic_ios&)’: /usr/include/c++/4.6/bits/ios_base.h:791:5: error: ‘std::ios_base& std::ios_base::operator=(const std::ios_base&)’ is private /usr/include/c++/4.6/bits/basic_ios.h:64:11: error: within this context In file included from /usr/include/c++/4.6/iterator:64:0, from /usr/include/qt4/QtCore/qlist.h:50, from /usr/include/qt4/QtCore/qvector.h:48, from /usr/include/qt4/QtGui/qpolygon.h:45, from /usr/include/qt4/QtGui/qmatrix.h:45, from /usr/include/qt4/QtGui/qtransform.h:44, from /usr/include/qt4/QtGui/qimage.h:45, from /usr/include/qt4/QtGui/QImage:1, from /home/tomasz/Development/C++/piet/src/core/pcodepointer.h:17, from /home/tomasz/Development/C++/piet/src/core/pblockmanager.h:9, from /home/tomasz/Development/C++/piet/src/core/pvirtualmachine.h:10, from /home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp:4: /usr/include/c++/4.6/ostream: In member function ‘std::basic_ostream& std::basic_ostream::operator=(const std::basic_ostream&)’: /usr/include/c++/4.6/ostream:57:11: note: synthesized method ‘std::basic_ios& std::basic_ios::operator=(const std::basic_ios&)’ first required here /home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp: In member function ‘void PVirtualMachine::setOutput(std::ostream)’: /home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp:216:11: note: synthesized method ‘std::basic_ostream& std::basic_ostream::operator=(const std::basic_ostream&)’ first required here
I'd be glad if someone pointed me out what is wrong, because I've got no idea...
My code looks like this:
- .h file
class PVirtualMachine { private: std::ostream output; [...] public: void setOutput(std::ostream); [...] };
- .cpp file
void PVirtualMachine::setOutput(std::ostream os) { output = os; }
-
ducin over 11 years/home/tomasz/Development/C++/piet/src/core/pvirtualmachine.cpp:33:1: error: uninitialized reference member ‘PVirtualMachine::output’ [-fpermissive] - so I have to pass it in constructor's initializing list?
-
WhozCraig over 11 yearsSure thing. I'd probably use a
std::reference_wrapper<>
and bind it to the given stream reference if it was absolutely mandatory we take a reference and the lifetime of the reference outside the object instance is known to exceed the object itself (like cout likely will, for example, etc). but the concept is the same regardless. -
WhozCraig over 11 yearsThe second disadvantage for references should be reflected in the code preceding it. I.e. there should be no
setOutput()
member, instead opting for a construct initializer-list. -
Karl Nicoll over 11 yearsWell you can still set the output later on, but yes, it does need to be constructed initially.
-
WhozCraig over 11 yearsOnce it is construct-initialized (which it must be), you cannot change it. references are initialize-only. Thus the need for
setOutput()
goes out the window in the fundamental case. -
Karl Nicoll over 11 years@WhozCraig Really? Interesting. I always thought that was possible. I guess I've never tried it! I'll update my answer.
-
WhozCraig over 11 yearsYeah, no dice. You can play the game with things like
std::reference_wrapper<>
if you absolutely had to take a reference, but for the case as you presented it, it is construct-init-only. -
0xcaff about 7 yearsIn your answer you say:
Reference can become invalid if the original instance goes out of scope.
Don't references keep the instance around even if the original goes out of scope? Where can I find more information about references and when they become invalid? -
Karl Nicoll about 7 years@caffinatedmonkey - Variables are not reference counted in C++, so the program does not know how many references point to a variable. When an object instance goes out of scope, all references to it will point to invalid memory. If you need reference counting, you should look at std::shared_ptr. For information on how references are used, check out this article.