Internal "Tee" setup - c++

I have inherited some really old VC6.0 code that I am upgrading to VS2008 for building a 64-bit app. One required feature that was implemented long, long ago is overriding std::cout so its output goes simultaneously to a console window and to a file. The implementation depended on the then-current VC98 library implementation of ostream and, of course, is now irretrievably broken with VS2008. It would be reasonable to accumulate all the output until program termination time and then dump it to a file. I got part of the way home by using freopen(), setvbuf(), and ios::sync_with_stdio(), but to my dismay, the internal library does not treat its buffer as a ring buffer; instead when it flushes to the output device it restarts at the beginning, so every flush wipes out all my accumulated output. Converting to a more standard logging function is not desirable, as there are over 1600 usages of "std::cout << " scattered throughout almost 60 files. I have considered overriding ostream's operator<< function, but I'm not sure if that will cover me, since there are global operator<< functions that can't be overridden. (Or can they?)
Any ideas on how to accomplish this?

You could write a custom stream buffer and attach it to cout with cout.rdbuf(). Your custom stream buffer would then tee the data to cout's original stream buffer and to a stream buffer stolen from an appropriate ofstream.
ofstream flog("log.txt");
teebuf tb(flog.rdbuf(), cout.rdbuf());
cout.rdbuf(&tb);
For your teeing stream buffer you can get an inspiration from this page.

You could use the pre-processor:
#define cout MyLogger
to inject new code.

Related

Is there a way to perform operations on a file opened with fopenf using stream operators?

I have a large C++ codebase that opens various files using the fopenf command (returning a FILE*), and performs operations throughout the code such as writing to and reading from the files using fputc, fgetc, etc. There are also a large amount of formatted print statements (fprintf). My task is to convert the code to use the C++ stream operators instead, creating a stream for each file and using the fmt library for formatted output (fmt::print), as well as the ">>" "<<" operators.
This is a large code base and I would prefer to do an iterative piece-by-piece conversion, i.e., have the new updated code working simultaneously with the old code, and producing exactly the same input/output without creating any extra/new files.
Is there a stop-gap way that I could temporarily get the code to run by writing to the file opened with the fopenf command using the stream operators? My thought would be to get it working that way, and then write a script to go back and replace whatever stop-gap is used with the final code, as well as replacing the open statements, once all the updates have been made.
Or, do I have to convert all of the I/O to use the fstream functionality first?
Is there a stop-gap way that I could temporarily get the code to run by writing to the file opened with the fopenf command using the stream operators?
That would require you to implement your own (or find a 3rd party) custom std::basic_streambuf class that writes to a pre-existing FILE* pointer. And then, wherever you want to use C++ stream operators on FILE* pointers, you can construct a plain std::ostream object passing it an instance of your custom class for its output buffer.

What does it mean to open an output file as both input and output?

I see code like this sometimes:
ofstream of("out.txt", ofstream::in | ofstream::out);
Why is it being opened as both input and output? What sense does it make to do that?
Sometimes one needs to read a file, do some processing, then update the original file with some new information. Opening the file for both input and output allows one to do that without closing and re-opening.
It also makes explicit one's intentions with regards to the file.
EDIT: My original answer didn't take into account that the OP's example uses ofstream instead of fstream. So …
Using ofstream with std::in doesn't make any sense. Are there reads performed on the stream? If not, perhaps the code when originally written used an fstream, which was later changed to an ofstream. It's the kind of thing that can creep into a code base that's in maintenance mode.
Since you're using an ofstream, none of the input functions are available to you on the stream. Then opening the file in read-write mode isn't harmful, but it is pointless unless you're going to start hacking about with the underlying stream.
It's probably boilerplate, copy/pasted from some tutorial on the internet without the author actually understanding it.
This means nothing for the actual streams. The std::ios_base::in openmode will simply be ignored. But for the underlying stream buffers, it does mean something to open as both input and output: For example, file stream and string stream buffers allow putback functionality, but it can only be used if the buffers' std::ios_base::openmode specifies output.

What does ifstream::open() really do?

Consider this code:
ifstream filein;
filein.open("y.txt");
When I use the open() function, what happens?
Does the file stream itself get opened?
or does the object's state change to open?
or both?
It's not clear if you want to know implementation details or standard requirements - but as for implementation details - it will call the underlying open system call on the operating system. On Linux for example this is called open. On Windows it is called CreateFile.
The filestream being open or closed is represented by it's state. So if you change the state to open, the filestream is now open. Like a doorway. If you open it, you've changed it's state to the open position. Then you can later close it, which involves changing it's state to the closed position. Changing its state to open and opening the stream are the exact same thing.
The std::ifstream is set up to own a std::filebuf which is a class derived from std::streambuf. The stream buffer is managing buffering for streams in a generic way and abstracts the details of how a stream is accessed. For a std::filebuf the underlying stream is an operating system file accessed as needed. When std::ifstream::open() is called this call is mainly delegated to std::filebuf::open() which does the actual work. However, the std::ifstream will clear() its state bits if the call to std::filebuf::open() succeeds and set std::ios_base::failbit if the call fails. The file buffer will call the system's method to allocate a file handle and, if successful, arrange for this file handle to be released in its destructor or in the std::filebuf::close() function - whatever comes first. When calling std::ifstream::open() with the default arguments the system call will check that the file exists, is accessible, not too many file handles are open, etc. There is an std::ios_base::openmode parameter which can be used to modify the behavior in some ways and when different flags are used when calling std::ofstream::open().
Whether the call to std::filebuf::open() has any other effects is up to the implementation. For example, the implementation could choose to obtain a sequence of bytes and convert them into characters. Since the user can override certain setting, in particular the std::locale (see the std::streambuf::pubimbue() function), it is unlikely that much will happen prior to the first read, though. In any case, none of the state flags would be affected by the outcome of any operation after opening the file itself.
BTW, the mentioned classes are actually all templates (std::basic_ifstream, std::basic_filebuf, std::basic_streambuf, and std::basic_ofstream) which are typedef'ed to the names used above for the instantiation working on char as a character type. There are similar typedefs using a w prefix for instantiations working on wchar_t. Interestingly, there are no typedefs for the char16_t and char32_t versions and it seems it will be a bit of work to get them instantiated as well.
If you think logically, ifstream is just the stream in which we will get our file contents. The parameters, we provide to ifstream.open() will open the file and mark it as open. When the file is marked as open, it will not allow you to do some operations on file like renaming a file as it is opened by some program. It will allow you to do the same after you close the stream. ifstream - imo is only the helper class to access files.

C++ how to check if a stream (iostream) is seekable

Is there a way I can check if an istream of ostream is seekable?
I suspect doing a test seek and checking for failbit is not correct
since the seek can fail for unrelated reasons.
I need this to work on Linux and mac, if that makes a difference.
Iostreams doesn't give you much. Stream objects are just wrappers around a buffer object derived from class std::streambuf. (Assuming "narrow" characters.) The standard derived buffer classes are std::stringbuf for strings and std::filebuf for files. Supposing you're only interested in files, std::filebuf is just a simple wrapper around the C library functionality. The C library does not define a way to determine if a FILE object supports seeking or not, besides attempting to do so, so neither does C++.
For what it's worth, the semantics of seek vary a bit. Some platforms might allow you to "seek" a pipe but only to the current position, to determine how many characters have been read or written. Seeking past the end might resize the file, or might cause the next write operation to resize the file, or something in between.
You might also try checking errno if badbit is set (or, as I prefer, use exceptions instead of flags).

MSVC istream implementation locking buffer

I'm working with some existing code which is deserializing objects stored in text files (I potentially need to read tens of millions of these). The contents of the file are first read into a wstring and then it makes a wistringstream from that. Running the Very Sleepy profiler on the program shows that it is spending about 20% of its time in the following call stacks:
Mtxlock or RtlEnterCritialSection
std::_Mutex::_Lock
std::flush
std::basic_istream<wchar_t, std::char_traits<wchar_t> >::get
<rest of my program>
and similar ones with std::_Mutex::_Unlock. I'm using Visual C++ 2008.
Looking in istream, I see that it constructs a sentry object which calls _Lock and _Unlock methods on the underlying basic_streambuf. This in turn just call _Lock and _Unlock on a _Mutex associated with that buffer. These are then defined as follows:
#if _MULTI_THREAD
// actually defines non-empty _Lock() and _Unlock() methods
#else /* _MULTI_THREAD */
void _Lock()
{ // do nothing
}
void _Unlock()
{ // do nothing
}
#endif /* _MULTI_THREAD */
It looks like _MULTI_THREAD is set in yvals.h as
#define _MULTI_THREAD 1 /* nontrivial locks if multithreaded */
Now, I know there will never be another thread trying to access this buffer, but it looks to me like there's no way around this locking while using the standard iostreams, which seems both odd and frustrating. Am I missing something? Is there a workaround for this?
Check the value for Runtime Library in Project properties, C/C++, Code Generation. If it's multi-threaded, change it to a non-multithreaded version.
In any version after Visual C++ 7.1 (!), you are out of luck as it's been removed, and you are stuck with the multithreaded CRT.
The std::flush seems senseless in your case. I can't see how you'd flush an istream, so I suspect it's a result of a tie. You may want to un-tie, i.e. call tie(NULL) on your wistringstream. That should also reduce the number of locks taken.
It turned out accessing the underlying buffer directly by replacing things like
c = _text_in->get();
with things like this
c = _text_in->rdbuf()->sbumpc();
fixed the problem and provided a big boost to performance.