Question

Im am a c programmer trying to begin a new phase of my life in c++ (i know i am still using printf below, but that because formatting is so easy). I am looking to print out the first byte of a datafile from a member function of an object. I think my streambuffer is being destroyed before I can read it's data but I'm lost as to what to do.

My class looks like the following

class MyParser {
    MyParser(string filepath);
    void readHeader();

    streambuf *pbuf;
    long size;
}

My constructor opens the file, gets the buffer out, outputs the first byte and returns. (I think pbuf is dying at the end of this code). This code outputs First Byte (in constructor): 0x8C

MyParser::MyParser(string filepath) {
    ifstream file(filepath.c_str(), ios::in | ios::binary)
    pbuf = file.rdbuf();
    size = pbuf->pubseekoff(0,ios::end,ios::in);
    pbuf->pubseekpos(0,ios::in);

    unsigned char byte = pbuf->sgetc();
    printf("First Byte (in constructor): 0x%02X\n", byte);

    return;
}

My read header is dumping the first byte, but based on the output all is see is First Byte (in readHeader): 0xFF

void MyParser::readHeader() {
    unsigned char byte = pbuf->sgetc();
    printf("First Byte (in readHeader): 0x%02X\n", byte);
}

My main simply creates a parser and tries to readHeader

void main() {
    MyParser parser("../data/data.bin");
    parser.readHeader();
}

I think the solution to my problem is to create a new streambuffer but new streambuf(file.rdbuf()) isn't working for me. Any advice?

Was it helpful?

Solution

Your program has undefined behavior: the stream buffer you keep is owned by the std::ifstream you open in body of you constructor. When this object dies, the stream buffer is released as well. The easiest approach to avoid this problem is to have your std::ifstream be a member of your class: this binds the life-time of the stream to your object. It may also be easier to use the std::istream interface for your parsing rather than the somewhat awkward std::streambuf interface.

If you really want to just use a stream buffer, you can allocate a std::filebuf using new filebuf and the open() the file stream directly. To keep a pointer to it, you would probably use std::unique_ptr<std::filebuf> (or std::auto_ptr<std::filebuf> if you are not using C++ 2011). Using the pointer class arranges for automatic release of the object. Of course, the pointers would still be members of your class to get the life-times right.

Your attempt to copy a stream buffer didn't work because stream buffers are not copyable. You'd need to create the file buffer directly:

MyParser::MyParser(std::string const& filename)
    : pbuf(new std::filebuf)
{
    this-pbuf->open("whatever", std::ios_base::in);
    ...
}

OTHER TIPS

You need some new C++ teaching material, because (sorry) but this is just so wrong. You need to declare the filestream as a member, there's no need for any new anywhere in this program, and pretty much nobody, ever, needs to deal with streambuf.

class MyParser {
    std::ifstream file;
public:
    MyParser(string filepath) {
        file.open(filepath, std::ios::in | std::ios::binary );
        char byte;
        file.read(sizeof(byte), &byte);
        printf("First Byte (in constructor): 0x%02X\n", byte);        
    }
    void readHeader() {
        char byte;
        file.read(sizeof(byte), &byte);
        printf("First Byte (in readHeader): 0x%02X\n", byte);   
    }
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top