Failing Contructor
-
Got a complex class which depends on data files opened in the constructor. Does anyone have any neat ideas about how to handle error conditions? If the files don't exist I don't want the object to be created but I can't see how to do it. TIA Dave Cross
-
Got a complex class which depends on data files opened in the constructor. Does anyone have any neat ideas about how to handle error conditions? If the files don't exist I don't want the object to be created but I can't see how to do it. TIA Dave Cross
I don't have any neat ideas, I just want to point out that the constructor is not the best place for doing a large amount of work that might fail. Michael :-)
-
Got a complex class which depends on data files opened in the constructor. Does anyone have any neat ideas about how to handle error conditions? If the files don't exist I don't want the object to be created but I can't see how to do it. TIA Dave Cross
Exceptions. Just throw an exception when your constructor fails and catch it in the code contructing the object. I think that is actually the *only* right way to do it. Cheers Steen. "To claim that computer games influence children is rediculous. If Pacman had influenced children born in the 80'ies we would see a lot of youngsters running around in dark rooms eating pills while listening to monotonous music"
-
Got a complex class which depends on data files opened in the constructor. Does anyone have any neat ideas about how to handle error conditions? If the files don't exist I don't want the object to be created but I can't see how to do it. TIA Dave Cross
Doing a lot of work in the constructor is generally considered bad OOP, but if you must do it than exception handling is the best technique to deal with errors, at least if this is going to be a widely distributed class. "But, daddy, that was back in the hippie ages..." My twelve year old son - winning the argument. "Stan, you are an intelligent guy who responds in meaningful ways" Paul Watson 16/10/01
-
Doing a lot of work in the constructor is generally considered bad OOP, but if you must do it than exception handling is the best technique to deal with errors, at least if this is going to be a widely distributed class. "But, daddy, that was back in the hippie ages..." My twelve year old son - winning the argument. "Stan, you are an intelligent guy who responds in meaningful ways" Paul Watson 16/10/01
IMHO doing a lot of work in ctors can't be (in general) consider bad OOP. A design approach that works nicely with OOP and ctors is the idea of having the objects keep an invariant condition that holds for the entire lifespan of the object. This invariants help deal with the object and ease the implementation of their methods --you can think of invariants as a semantic contract with a class instance. So, if initializing an invariant condition takes a lot of work due to the complexity of the invariant, the proper place to do that is precisely the ctor. After construction you know everything's in place, without resorting to
init()
methods and stuff like that. If you cannot grant that invariant on construction time,throw
ing is the exact thing to do. I would even dare to say that huge ctors (if properly backed up by meaningful semantics) provide for richer, easier to use classes. Joaquín M López Muñoz Télefónica, Investigación y Desarrollo -
Got a complex class which depends on data files opened in the constructor. Does anyone have any neat ideas about how to handle error conditions? If the files don't exist I don't want the object to be created but I can't see how to do it. TIA Dave Cross
Effectively throwing an exception is the way to let the client knows about the error. If lot of stuff is done in the constructor, you probably also want to do some cleanup if an error occurs and in that case one of the following design may help (choose the one that best fit). 1) Uses ressource wrapper classes for ressources (like std::auto_ptr for pointers). Thus every member that allocate a ressource (memory, handle) is a wrapper. 2) Uses the pimpl idiom. The implementation class should then have a trivial constructor that may not have an error (set pointer to NULL, handle to INVALID_HANDLE_VALUE,...) and an initialisation function that do the actual initialisation. class VClass { private: class VImpl; VImpl *m_pImpl; }; class VClass::VImpl { public: VImpl(); // Simple initialisation only ~VImpl(); // Release every allocated ressource void init(); // Complex initialisation }; VClass::VClass() { std::auto_ptr pImpl = new VImpl; pImpl->init(); m_pImpl = pImpl.release(); } VClass::~VClass() { delete m_pImpl; } 3) Derive from a class that hold the ressource and do the initialisation in the derived class constructor by calling an initialisation function in the inherited class. That way if an exception is thrown from the derived class, the base class that hold the ressource will have its destructor called since it is a completly constructed object. 4) Uses wrapper class in the constructor body and at the end of the constructor body transfer the ownership from the wrapper class to the associate member of the class. I do not like complex constructor without using one (or more) of the design above since it complexify the constructor error handling a lot (for ex. closing file that have been opened up to that point). Note that the patterns #2 and #4 above typically allows to reduce compilation depedencies in the header file... which is often desirable when a class is complex. Philippe Mori
-
IMHO doing a lot of work in ctors can't be (in general) consider bad OOP. A design approach that works nicely with OOP and ctors is the idea of having the objects keep an invariant condition that holds for the entire lifespan of the object. This invariants help deal with the object and ease the implementation of their methods --you can think of invariants as a semantic contract with a class instance. So, if initializing an invariant condition takes a lot of work due to the complexity of the invariant, the proper place to do that is precisely the ctor. After construction you know everything's in place, without resorting to
init()
methods and stuff like that. If you cannot grant that invariant on construction time,throw
ing is the exact thing to do. I would even dare to say that huge ctors (if properly backed up by meaningful semantics) provide for richer, easier to use classes. Joaquín M López Muñoz Télefónica, Investigación y DesarrolloI'm not religious about it one way or the other. I certainly understand that one methodology will never solve every possible design problem. My personal philosophy though remains that a complex ctor made dependent upon exception handling is generally not superior to a simple "init()" call. But I am not prepared to say that it is always inferior. I have always found it very convenient to be able to return a complex object to its original default state at any point in its lifetime with an initialization function of some kind. You just have to remember that the init() cannot be virtual if you intend to use it from the ctor. "But, daddy, that was back in the hippie ages..." My twelve year old son - winning the argument. "Stan, you are an intelligent guy who responds in meaningful ways" Paul Watson 16/10/01