Design Pattern: Init &Tear Down Functions

Started by
15 comments, last by Anon Mike 17 years, 8 months ago
Lets say I have a class similar to this:

class CTest{
public:
CTest(){}
~CTest(){}

Init(); // allocate memory
TearDown(); // deallocate memory and stuff
};






Now I would perform something like this when I create an object and when I am through with it... CTest ct; c.Init(); c.TearDown(); or similarly... CTest* ct = new CTest(); ct->Init(); ct->TearDown(); But the thing is I could have easily placed Init() and TearDown() bodies inside the Constructor and Deconstructor. Having them as seperate functions means I have to rely on the caller to remember to do both of thoes things. What design pattern should I follow? edit: More trouble can follow if a person decides to use a member function that would rely on Init() having been called. If they decide to use another function without calling Init() first that would lead to dangerous behaviour .... But the question is still the same ... what is the proper design pattern?
Advertisement
I would put them in the constructor/deconstructor unless they take parameters. But thats just how I like to do it.
Why not put what needs to be initialized in the constructor, and what needs to be deinitialized in the destructor? This eliminates the possibility of the user initialized more than once or less than once.
I prefer to have explicit Init/DeInit functions. That way I can return error codes if necessary, and try to deal with init calls failing. You can always call your init/deinit functions from within your c-tors and d-tors.
If it's possible at all put them in constructor / destructor. If it's not possible I'd prefer rethinking the design so that it can be done.
The name of the pattern is raii (Resource Acquisition Is Initialization) btw, or more broadly resource management.

EDIT: One benefit of raii is that, if done properly, there will be no leaks or whatever even in the face of exceptions.
Quote:Original post by agi_shi
Why not put what needs to be initialized in the constructor, and what needs to be deinitialized in the destructor? This eliminates the possibility of the user initialized more than once or less than once.


Thats what I thought, but I'm reading a book which has code examples/tutorials from "real programmers" exhibiting this pattern.

This seems like a very "C" thing to do and doesnt look like a good idea in "C++"

But more importanly should one have to design classes as though the people using them are going to be idiots? Or should they be idiot proof?
Quote:Original post by fpsgamer
Quote:Original post by agi_shi
Why not put what needs to be initialized in the constructor, and what needs to be deinitialized in the destructor? This eliminates the possibility of the user initialized more than once or less than once.


Thats what I thought, but I'm looking at code examples/tutorials from "real programmers" exhibiting this pattern.

This seems like a very "C" thing to do and doesnt look like a good idea in "C++"

But more importanly should one have to design classes as though the people using them are going to be idiots? Or should they be idiot proof?


In my opinion if you code something in C++ to use by somebody else, you simply assume they are not idiots. Programming, and certainly in C++, is difficult enough. So whatever helps automate some tasks and reduce complexity is welcome for anybody. Just look at how many bugs exist in software, I think raii helps a lot and it can be done in a good way in C++.
It only makes sense to separate the initialization from the constructor if, in the course of normal operation, it's reasonable for the initialization to fail. The text book example is the file object, where opening the file can reasonably fail in the course of normal operation. Otherwise, if the initialization is expected to succeed and the initialization is required before using any of the member functions, then there's no reason to separate initialization from construction.
Quote:Original post by Driv3MeFar
I prefer to have explicit Init/DeInit functions. That way I can return error codes if necessary, and try to deal with init calls failing. You can always call your init/deinit functions from within your c-tors and d-tors.


Are the problems that your return codes indicate exceptional? As in, are they an exception to what should happen?

In that case you use exceptions:
class a { public:    a(): b(makeC()) {        if (b == NULL) // oh no!            throw std::runtime_error("b == NULL"); // throw exception    }    ~a() {        // b will be freed by the auto_ptr when the auto_ptr gets destroyed    }    private: std::auto_ptr<c> b;    ...};int main() {    try { // check for exceptions        a A;        A.doAwesomeStuff();    }    // catch std::exception s.  note: std::runtime_error is an std::exception    catch(std::exception& e) { std::cout << e.what(); }    // catch anything else    catch(...) { std::cout << "unknown error"; }}


Read More.
And then you end up with a half-initialized object, if you are not very very careful.
See:
http://www.awprofessional.com/content/images/020163371x/supplements/Exception_Handling_Article.html

This topic is closed to new replies.

Advertisement