How are you supposed to use set_rdbuf()? - c++

So I am creating a class that inherits from ifstream, and that gives me acces to the protected function set_rdbuf, and at first I just thought it allowed you to set your own filebuf that then would be used, but that does not seem to work for me. I wrote the following code:
class A : public std::fstream {
private:
std::filebuf m_file_buf;
public:
A() {
if (!m_file_buf.open("test_file.txt", ios_base::out | ios_base::in)) {
std::cout << "something went wrong";
}
// std::fstream::rdbuf()->swap(m_file_buf);
std::fstream::set_rdbuf(&m_file_buf);
std::cout << "m_ file buff is: " << m_file_buf.is_open() << "\n";
std::cout << "rd file buff is: " << std::fstream::rdbuf()->is_open() << "\n";
std::cout << "we are: " << std::fstream::is_open() << "\n";
}
};
int main() {
A a;
return 0;
}
This will log:
m_ file buff is: 1
rd file buff is: 0
we are: 0
I was under the assumption that when I called rdbuf() I would then get the one I had set it to. However, if I use the swap function that rdbuf() provides, then it prints as I expect it to
class A : public std::fstream {
private:
std::filebuf* m_file_buf;
public:
A() {
m_file_buf = new std::filebuf();
if (!m_file_buf->open("test_file.txt", ios_base::out | ios_base::in)) {
std::cout << "something went wrong";
}
std::fstream::rdbuf()->swap(*m_file_buf);
std::cout << "m_ file buff is: " << m_file_buf->is_open() << "\n";
std::cout << "rd file buff is: " << std::fstream::rdbuf()->is_open() << "\n";
std::cout << "we are: " << std::fstream::is_open() << "\n";
// Get it back again as we swapped it out
m_file_buf = std::fstream::rdbuf();
}
};
int main() {
A a;
return 0;
}
m_ file buff is: 0
rd file buff is: 1
we are: 1
//and when I at the end swap back, everything is 1/open
I swited to pointer in the swap code so that I could point to the return of rdbuf()
This was compiled on MSVC version 19.28 with arg /std:c++17
So am I wrong is how set_rdbuf is supposed to be used, or is there something else I am doing wrong?

Related

cant use Friend function declare in a class

i have a problem , I have a class who I want to work , It's Log class to writ in .txt file the informations i need to debug / follow the process.
However I have difficulties with the "SupSrvLogInfo" method which i cant make work if you can please help me. I pretty sure it's juste a question of member access or something like that...
here is the class
class FileLogger {
public:
enum e_logType { SupError , SupEvtInfo , SupWarn , SupStatPer , SupStatEvt , SupEvtDbg };
FileLogger (const char *version_, const char *fname = "log.txt")
: numWarnings (0U),
numErrors (0U)
{
myFile.open (fname);
// premieres lignes
if (myFile.is_open()) {
myFile << "version " << version_ << std::endl;
myFile << "Log file created" << std::endl << std::endl;
myFile << currentDateTime() << std::endl ;
}
}
~FileLogger () {
if (myFile.is_open()) {
myFile << std::endl << std::endl;
// A la fin calcul nombre error et warnings
myFile << numWarnings << " warnings" << std::endl;
myFile << numErrors << " errors" << std::endl;
myFile << currentDateTime() << std::endl ;
myFile.close();
} // if
}
friend FileLogger &operator << (FileLogger &logger, const char *text) {
logger.myFile << text << std::endl;
return logger;
}
friend void SupSrvLogInfo(FileLogger &logger,const e_logType l_type){
logger.myFile << currentDateTime();
switch (l_type) {
case FileLogger::e_logType::SupError:
logger.myFile << "[ERROR]: ";
++logger.numErrors;
break;
case FileLogger::e_logType::SupWarn:
logger.myFile << "[WARNING]: ";
++logger.numWarnings;
break;
case FileLogger::e_logType::SupEvtInfo:
logger.myFile << "[INFO]: ";
break;
case FileLogger::e_logType::SupStatPer:
logger.myFile << "[PERIODIC_STAT]: ";
break;
case FileLogger::e_logType::SupStatEvt:
logger.myFile << "[SPECIFIC_STAT]: ";
break;
case FileLogger::e_logType::SupEvtDbg:
logger.myFile << "[DEBUG_INFO]: ";
break;
} //
}
private:
std::ofstream myFile;
unsigned int numWarnings;
unsigned int numErrors;
}; // class end
And then I declare my object to have my text file. But cant get the method work , Code block dont even see my function saying wasnt declare in this scope, i suppose its because of the friend ? :
FileLogger SupSrvFile("V0", "///home/etcap/Documents/code/SupSrv/SupSrV.txt" ); // Creating my object working fine
// Trying now to have for example an Error message in my log file
SupSrvFile.supSrvLogInfo(SupSrvfile, SupError) // NOT WORKING AT ALL
supSrvLogInfo(SupSrvfile, SupError) // NOT WORKING AT ALL
supSrvLogInfo(SupSrvfile.SupError) // NOT WORKING AT ALL

C++ overwriting data from parent structure is not working

Normally it has no sense and is very unsafe, but only theoretically if there is a way,
Here is example:
#include<iostream>
struct A {
uint32_t &get() {
return *reinterpret_cast<uint32_t *>(this);
}
void set(const uint32_t val) {
*this = *reinterpret_cast<const A *>(&val);
}
};
struct B : A {
uint16_t a;
uint16_t b;
void set_b(const uint32_t val) {
*this = *reinterpret_cast<const B *>(&val);
}
};
main() {
B k;
k.a = 0x1234;
k.b = 0x5678;
std::cout << std::hex << k.get() << " : " << k.a << " " << k.b << std::endl;
k.set_b(0x87654321);
std::cout << std::hex << k.get() << " : " << k.a << " " << k.b << std::endl;
k.set(0xaabbccdd);
std::cout << std::hex << k.get() << " : " << k.a << " " << k.b << std::endl;
}
I get this result:
56781234 : 1234 5678
87654321 : 4321 8765
87654321 : 4321 8765
But I except that last should be:
aabbccdd : ccdd aabb
So, why overwriting data in structure from parent not working?
Experiment:
I make one experiment, that I add one variable into struct A, then set function was working as expected (but final structure was bigger)
Of course there exists different ways how to deal with this (for example with unions) but I only playing with this and I interested why this is not working.
In the class A the set function is really
void set(const uint32_t val) {
(*this).operator=(*reinterpret_cast<const A *>(&val));
}
That will invoke the automatically generated A::operator= function. But since A doesn't have any member variables to be copied, it does nothing.
And now that you've done your experiment, please don't do anything like that ever again.

libc++: Why is the stream still good after closing

I have a very simple program
#include <iostream>
#include <fstream>
void CHECK(std::iostream& s)
{
std::cout << "good(): " << s.good()
<< " fail(): " << s.fail()
<< " bad(): " << s.bad()
<< " eof(): " << s.eof() << std::endl;
}
int main(int argc, const char * argv[])
{
std::fstream ofs("test.txt", std::ios::out | std::ios::trunc);
std::cout << "opened" << std::endl;
CHECK(ofs);
ofs << "Hello, World!\n";
CHECK(ofs);
ofs.close();
std::cout << "closed" << std::endl;
CHECK(ofs);
ofs << "Hello, World!\n";
std::cout << "after operation" << std::endl;
CHECK(ofs);
return 0;
}
With libc++ I get the following last line:
good(): 1 fail(): 0 bad(): 0 eof(): 0
Expected (or with libstdc++):
good(): 0 fail(): 1 bad(): 1 eof(): 0
I have tested on OSX with Xcode 9.4.1 (or on Linux), but always the same. Can anybody explain me the situation here? Also the file content was not updated, because already closed. Why is the stream still good after closing and further operation?
What I suspect is happening is that the operations are stuffing the data into the rdbuf associated with the stream. That succeeds, as long as there is room in the buffer. Eventually, the buffer gets full, and the stream attempts to write to the file (which is closed) and that fails.
You can test that by making the last bit a loop:
ofs.close();
std::cout << "closed" << std::endl;
CHECK(ofs);
for (int i = 0; i < 500; ++i)
{
ofs << "Hello, World!\n";
std::cout << i << " ";
CHECK(ofs);
}
std::cout << "after operation" << std::endl;
On my machine, it fails after about 300 - and forever after that.
Is this correct behavior? (or even standards-compliant?)
I don't know.
[ Later: If I change libc++ do set the buffer size to 0 upon close, then the first write fails - so that suggests that my analysis is correct. However, I still haven't found anything in the standard about what this 'should' do. ]

c++ simple stream manipulation with ostream and istream?

I have been looking for a solution but couldn't find what I need/want.
All I want to do is pass a stream intended for std::cout to a function, which manipulates it. What I have used so far is a template function:
template<typename T>
void printUpdate(T a){
std::cout << "blabla" << a << std::flush;
}
int main( int argc, char** argv ){
std::stringstream str;
str << " hello " << 1 + 4 << " goodbye";
printUpdate<>( str.str() );
return 0;
}
What I would prefer is something like:
printUpdate << " hello " << 1 + 4 << " goodbye";
or
std::cout << printUpdate << " hello " << 1 + 4 << " goodbye";
I was trying to do:
void printUpdate(std::istream& a){
std::cout << "blabla" << a << std::flush;
}
but that gave me:
error: invalid operands of types ‘void(std::istream&) {aka void(std::basic_istream<char>&)}’ and ‘const char [5]’ to binary ‘operator<<’
You can't output data to an input stream, just not a good thing to do.
Change:
void printUpdate(std::istream& a){
std::cout << "blabla" << a << std::flush;
}
To:
void printUpdate(std::ostream& a){
std::cout << "blabla" << a << std::flush;
}
Note the stream type change.
Edit 1:
Also, you can't output a stream to another stream, at least std::cout.
The return value of << a is a type ostream.
The cout stream doesn't like being fed another stream.
Change to:
void printUpdate(std::ostream& a)
{
static const std::string text = "blabla";
std::cout << text << std::flush;
a << text << std::flush;
}
Edit 2:
You need to pass a stream to a function requiring a stream.
You can't pass a string to a function requiring a stream.
Try this:
void printUpdate(std::ostream& out, const std::string& text)
{
std::cout << text << std::flush;
out << text << std::flush;
}
int main(void)
{
std::ofstream my_file("test.txt");
printUpdate(my_file, "Apples fall from trees.\n");
return 0;
}
Chaining Output Streams
If you want to chain things to the output stream, like results from functions, the functions either have to return a printable (streamable object) or the same output stream.
Example:
std::ostream& Fred(std::ostream& out, const std::string text)
{
out << "--Fred-- " << text;
return out;
}
int main(void)
{
std::cout << "Hello " << Fred("World!\n");
return 0;
}

std::ostream tellp() giving wrong output in VS2010

Below is the code i am running and corresponding output.
#include<iostream>
#include <sstream>
#include <strstream>
#include <streambuf>
template <typename char_type>
struct ostreambuf : public std::basic_streambuf<char_type,std::char_traits<char_type> >
{
ostreambuf(char_type* buffer, std::streamsize bufferLength)
{
// set the "put" pointer the start of the buffer and record it's length.
setp(buffer, buffer + bufferLength);
}
};
int main()
{
char strArr[] = "Before-1";
char stringArr[] = "Before-2";
std::strstream strStream(strArr,sizeof(strArr));
ostreambuf<char> ostreamBuffer(stringArr, sizeof(stringArr));
std::ostream stringStream(&ostreamBuffer);
const std::streampos posStringBefore = stringStream.tellp();
std::cout << "Before: "
<< "strArr = "
<< strArr
<< " & "
<< "stringArr = "
<< stringArr
<< std::endl;
std::cout << "Before: " << "posStringBefore = "
<< posStringBefore
<< std::endl;
// -------------------------
strStream << "After-1";
stringStream << "After-2";
const std::streampos posStringAfter = stringStream.tellp();
std::cout << "After : "
<< "strArr = "
<< strArr
<< " & "
<< "stringArr = "
<< stringArr
<< std::endl;
std::cout << "After : " << "posStringAfter = "
<< posStringAfter
<< std::endl;
return 0;
}
This is the o/p on VS2010 :
Before: strArr = Before-1 & stringArr = Before-2
Before: posStringBefore = -1
After : strArr = After-11 & stringArr = After-22
After : posStringAfter = -1
In reference to link
Setting the internal buffer used by a standard stream (pubsetbuf)
How to get the size of std::ostream object created?
It doesn't give you a "wrong" output/value. tellp uses rdbuf()->pubseekoff which relays the call to virtual seekoff. The basic_streambuf implementation simply returns -1 as defined in the C++ standard. You need to provide an own implementation for this method in your ostreambuf class.
See cppreference: basic_streambuf::pubseekof