Treating this as an intellectual exercise where you don't want to use std::vector
, you need to divide your classes up so they have a single responsibility. Here's my "integer array" class. Its responsibility is to manage the memory for an integer array.
class IntArray {
public:
IntArray() : ptr_(new int[100]) {}
~IntArray() { delete[] ptr_; }
IntArray(const IntArray&) = delete; // making copyable == exercise for reader
IntArray& operator=(const IntArray&) = delete;
// TODO: accessor?
private:
int* ptr_;
};
Here is my file handling class. Its responsibility is to manage a FILE*
.
class FileHandle {
public:
FileHandle(const char* name, const char* mode)
: fp_(fopen(name, mode))
{
if (fp_ == 0)
throw std::runtime_error("Failed to open file");
}
~FileHandle() {
fclose(fp_); // squelch errors
}
FileHandle(const FileHandle&) = delete;
FileHandle& operator=(const FileHandle&) = delete;
// TODO: accessor?
private:
FILE* fp_;
};
Note, that I convert my construction error to an exception; fp_
being a valid file pointer is an invariant that I wish to maintain so I abort construction if I cannot set this invariant up.
Now, makeing File_ptr
exception safe is easy and the class needs no complex resource management.
class File_ptr {
private:
FileHandle p;
IntArray i;
public:
File_ptr(const char* n, const char* s)
: p(n, s)
, i()
{}
};
Note the lack of any user-declared destructor, copy assignment operator or copy constructor. I can swap the order of the members and in either case it doesn't matter which constructor throws.