I would not go with the invalid object approach in general because I would consider this as bad design. After construction, the object must be in a state where the invariants are established (that is the only purpose a constructor should serve). Consider a class strange_vector
implementing something like std::vector
, but after calling strange_vector<int>(10, 0)
, the object would be in an unusable state because the allocation failed.
Instead I would declare the constructors private and use a factory method which returns an optional:
class file
{
public:
~file() {fclose(m_file);}
static std::optional<file> open(std::string const& filename)
{
auto f = fopen(filename.c_str(), "r");
if (f)
{
return std::make_optional<file>(f);
}
else
{
return std::nullopt;
}
}
private:
file(FILE* file);
FILE* m_file;
};
One of the biggest benefits of exception handling is (besides decoupling error handling and normal code path) that you cannot ignore them accidentally. If you want that, you could create your own class similar to optional
that, when not initialized with a valid object, logs an error message and terminates your program (or any other reasonable error handling). I think there is a talk from A. Alexandrescu about systematic error handling where he implements a class Expected<T>
that contains either a value of type T
or an exception. You could use this a basis and instead of the exception add your error handling there.
std::optional
is not part of the standard yet, but you can easily get implementations either as part of recent compilers, in boost, or in other libraries.
is_open
function. – Tainataint