First, your ConstructA class makes no sense at all to me. There really are two cases basically:
- The construction of an object fails
- The object is left in an defined, but restricted state. Strictly, the construction succeeded, but possibly not the the degree that the caller wished. He can optionally later complete the construction.
1. The construction fails
I'll use your ConstructA in the following code just to make the point of signaling about construction failure:
A a0;
try {
A::ConstructA a1(a0);
} catch(...) {
// fail to construct a1
}
Constructors throw exceptions to signal when their constructions fail. The idea is that if construction of an object fails, then the object is not constructed. In other words, the object does not exist. If you have to initialize a1 in an constructor init list, there is a way too:
struct B {
B() try : a1(a0) {
// other constructor code...
} catch(...) {
// fail to construct either a0 or a1, or constructor
// code threw
}
A a0;
A::ConstructA a1;
};
try {
B b;
} catch(...) {
// fail to construct B
}
First, code in the catch block of the constructor is executed, then the exception is automatically propagated to the code that created the B object, and its catch blocks are considered.
Your class ConstructA's constructor could look like this, for example:
struct ConstructA {
ConstructA(A &a):a(a) {
if(!condition_met) {
throw std::runtime_error("condition_met false");
}
}
A &a;
};
2. The object is in a restricted state
That is exactly the case what you have when you have a file stream object, but which is not connected to a file. If in the constructor you find that the file mentioned doesn't exist, you can still fully construct the stream, but set it in a not-opened state. Some operations could be disallowed then and you can have a isOpen
or isValid
function that you can use to query the state of the object.
This can be applied to other cases too. Some framework i used has a Color
class. Default constructing a color class left it in a invalid state, so that it doesn't compare equal to any valid color:
Color c;
assert(c.isValid() == false);
The same technique is used for a null pointer. It's set to a defined, but restricted state when you assign NULL to it:
int *a = NULL;
assert(a == NULL);
You cannot dereference a null pointer for example.