In this code I present below I am having a problem. It manifests as a bad_alloc exception, and this is because the argument passed to reader, the CompressedBufferReader, is a bad string.
class FileReader {
FILE *file;
protected:
unsigned char *data; // local copy
long size;
public:
FileReader(const char *filename);
~FileReader();
unsigned long getSize();
unsigned char *getFileData();
};
class CompressedBufferReader {
unsigned char *buffer;
unsigned long len;
public:
CompressedBufferReader(unsigned char *);
~CompressedBufferReader();
unsigned char *getBuffer();
unsigned long getLength();
};
CompressedBufferReader::CompressedBufferReader(unsigned char *srcCompressed) {
len = 0; buffer = 0;
len = GetDecompressedBufferSize(srcCompressed);
buffer = new unsigned char[len]; if (!buffer) throw std::runtime_error("Cannot allocate!");
WriteDecompressedBuffer(buffer, len, srcCompressed);
}
CompressedBufferReader::~CompressedBufferReader() {
delete[] buffer;
}
unsigned char *CompressedBufferReader::getBuffer() {return buffer;}
unsigned long CompressedBufferReader::getLength() {return len;}
// similar interface to FileReader. Does not inherit because it does not benefit from doing so.
class CompressedFileReader {
CompressedBufferReader reader;
public:
CompressedFileReader(const char *filename);
unsigned char *getFileData();
unsigned long getSize();
};
CompressedFileReader::CompressedFileReader(const char *filename) : reader(FileReader(filename).getFileData()){} // this line is causing the problem
unsigned char *CompressedFileReader::getFileData() { return reader.getBuffer(); }
unsigned long CompressedFileReader::getSize() { return reader.getLength(); }
To be more specific, it seems like the FileReader which I create anonymously becomes deallocated before its data contents can be passed to the constructor of reader, a CompressedBufferReader.
the problem is that I cannot write CompressedFileReader‘s constructor in a way that allows me to properly instantiate a FileReader, because I intend to use CompressedBufferReader‘s constructor and that means I must call it before the body of the constructor. Bit of a catch-22. How is this issue resolved?
I don’t see a problem in the way you use the constructors, which should cause the bad_alloc (though the code does seem clumsy). Let us look at the execution of the line that is causing the problem –
The following steps take place:
FileReaderis created. Its constructor is called withfilename, which is aconst char*.datamember of theFileReader.getFileData()is called on the tempFileReader, returning the value ofdata, I assume, which is anunsigned char *.reader, which is aCompressedBufferReader, is constructed using theunsigned char *.FileReaderis destructed.So, the problem is not with the order of the constructions, or the lifespan of the temporary
FileReader. There are a few unknown which you should look into:FileReadercreate a valid buffer, and stores it indata?getFileData()return the buffer created?GetDecompressedBufferSize()return the correct value for a valid buffer?WriteDecompressedBuffer, whose code we don’t have?Lastly, you might want to simplify your code. Constructions like that aren’t very readable. And, of course, the use of standard container like vectors would make it safer.