Steven Lu
Steven Lu

Reputation: 43547

Object oriented programming concepts and resource management

So I have a FileReader class, it looks like this:

#define DISALLOW_COPY(type) \
    type(const type&); \
    void operator=(const type&)

class FileReader { 
    FILE *file; 
    DISALLOW_COPY(FileReader);
protected:
    unsigned char *data; 
    long size;
public:
    FileReader(const char *filename);
    ~FileReader();
    unsigned long getSize();
    unsigned char *getFileData();
};


FileReader::FileReader(const char *filename) {

    file = NULL; data = NULL;
    if (!(file = fopen(filename, "rb"))) { throw std::runtime_error("File could not be opened."); }
    fseek(file,0,SEEK_END);
    size = ftell(file);
    rewind(file);
    data = new unsigned char [size];
    VERIFY(size == (long)fread(data, 1, size, file));
    fclose(file);
#ifdef DEBUG
    PRINT("FileReader opening file "); printf("%s, %ld bytes.\n",filename,size);
#endif
}
FileReader::~FileReader() {
    delete[] data;
}
unsigned char *FileReader::getFileData() { return data; }
unsigned long FileReader::getSize() { return size; }

By itself it functions quite well.

When i create a FileReader I must do so with a filename that specifies what file it has to open, and when I am finished with it, it automatically cleans up after itself.

But I find I'm having a bit of trouble putting this class to good use. You see, if I try to use it from another class, for instance an Image class which represents a raster image, I'm not always creating an Image by reading it from a file. So, I don't want to inherit FileReader from Image.

Neither can I make FileReader a member of Image, because I still need to initialize (and read out a file) when I initialize my Image.

What I can do, however, is use FileReader in passing in Image::loadFile(), but then I must allocate a new buffer to store all the data, since FileReader will be cleaned up at the end of the function call.

At first I thought that RAII was a great idea, but now, I'm not so sure. It's great for handling exceptions, but I want to prevent having to move my data around like this, while keeping a clean interface that will help prevent memory management nightmares. Is there a way to do that? Seems to me like I have to significantly restructure things in order to avoid juggling all the data across a series of dynamically allocated buffers. Should I use smart pointers?

Upvotes: 1

Views: 319

Answers (2)

Nabheet
Nabheet

Reputation: 1314

You could possibly make FileReader * a private member and overload your constructor.

public:
    Image();
    Image(const char* fileName);

So, the consumer for your Image class decides what happens. In the second constructor you initialize your FileReader * and then destroy it in the destructor only if was initialized. I guess this might be RAII in the sense that the constructor on your object initializes which resource the object needs.

Hope this helps.

Upvotes: 0

Chris H
Chris H

Reputation: 6601

RAII IS a good idea. You need to split up your file and your "open file" objects. Make a new class called OpenFile, with a constructor like the following OpenFile(FileReader &f); Your resource is an open file, not the filename.

Upvotes: 2

Related Questions