Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

wah_on_2

Constructor Vs Init()

This topic is 5667 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all, I meet a problem when i writing classes for my porject. I learned that i should do the initialization in constructor in a class. However, the constructor never has the return value. The problem is that if the constructor meet an error and then who will know what happened? So some people suggested that i can use int init(); function to replace the constructor. Mm....i think this is a solution but this will break the meaning of constructor. I don''t want to follow this solution. How can i do? In fact, i have another solution but it seem dirty ^_^". e.g. class CLV1 { private: bool m_Status; //for check initial success or not int m_Num; public: CLV1(CLV2 *lv2) { if(lv2 != NULL) { m_Num = lv2->GetNum(); m_Status = true; } else m_Status = false; } bool CheckSuccess(){ return m_Status; }; //for determine success or not }; //main.cpp CLV2 *lv2 = new CLV2(); CLV1 *lv1 = new CLV1(lv2); if(lv1->CheckSuccess() == true) {..........} else {...........} Haha,is it a dirty way? Any other suggestion for me? Thx a lot of ^^

Share this post


Link to post
Share on other sites
Advertisement
Constructor can throw an exception if an error occurs.

CheckSuccess() isn''t so terrible solution either. fstream uses it, i.e. constructor may set fail-flag if it fails.

Share this post


Link to post
Share on other sites
yes. i can catch the exception. However, i think no one will try and catch exception when creating object. It is terrible and strange. ¤@,¤@"

I discovered that many programs are using init function for replacing the constrcutor. I think it is the best way to solve the problem although it is meaningless. ^_^"

How about your opinions?

Share this post


Link to post
Share on other sites
quote:
Original post by wah_on_2
yes. i can catch the exception. However, i think no one will try and catch exception when creating object.

Then their program will terminate.
quote:

How about your opinions?

Using an init() function is bad form as it pushes responsibility for object integrity onto the client of the class. That means the client can forget to check the integrity, or that the client code becomes more complicated. It''s also bad form from the OO perspective, since each operation on an object should be atomic, in that it correctly transitions from one state to the next without ever sitting in an intermediate (unstable) state. That''s the basis of exception-safety.

Share this post


Link to post
Share on other sites
quote:
Using an init() function is bad form as it pushes responsibility for object integrity onto the client of the class. That means the client can forget to check the integrity, or that the client code becomes more complicated. It's also bad form from the OO perspective, since each operation on an object should be atomic, in that it correctly transitions from one state to the next without ever sitting in an intermediate (unstable) state. That's the basis of exception-safety.


That is a good discussion of "WHY" you would want to keep it as constructor only but falls short with a solution to an error in the creation of the object.
For that you need to go one step higher and try to get out of the theoretical cases and understand the need for catching errors in object correction.
I'm working on a game with a separate editor and game.
When there's an error in the editor, I want it to crash with debug information. I want to know why there's a problem and where it's at. And since I'm going to be creating and using the same objects in both my game and editor, I would want those to tested many times.
So let's look at a game-crashing error: I want to find it as close as possible to the source. And I think it's inadequate that I only have a boolean at the beginning of the creation of the object to be of any help. At the level of object creation, it is a step-by-step process and I want to know the error at the correct step. That requires more testing/throwing at each step and you have to be aggressive in identifying each step and how it can go wrong. That means more information is generated at each error and that's a good thing. Your testers will thank you for it and the users/gamers that do experience errors will be able to identify and help you find them.
One way to identify possible error is to do a step-through of the object creation. I usually have a testing region in my GameInit() code where I can create the object separately from other game processes. Sometimes it does take a bit of a setup to do so, but it's usually worth it. As you step through in the debugger, you can see the full object data and it's a lot less of a theoretical discussion and you can identify the possible errors.
When you complete a process like that and include a lot of proper testing, then you don't have the fragility that makes the whole program seem like a house of cards.

ZoomBoy
Developing a iso-tile 2D RPG with skills, weapons, and adventure. See my old Hex-Tile RPG GAME, character editor, diary, 3D Art resources at Check out my web-site


[edited by - ZoomBoy on February 7, 2003 10:56:23 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by ZoomBoy
That is a good discussion of "WHY" you would want to keep it as constructor only but falls short with a solution to an error in the creation of the object.

That''s because this discussion wasn''t lacking a solution. You throw an exception.

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan
Using an init() function is bad form as it pushes responsibility for object integrity onto the client of the class. That means the client can forget to check the integrity, or that the client code becomes more complicated. It''s also bad form from the OO perspective, since each operation on an object should be atomic, in that it correctly transitions from one state to the next without ever sitting in an intermediate (unstable) state. That''s the basis of exception-safety.


I think I''m going to disagree with you on some of this. It is never the USED class''s responsibility to fully prevent errors from occuring within itself. This is an unrealistic constraint. It is always the USING class''s responsibility to verify that every function call it executed succeeded and is valid.
It IS the USED classes responsibility to monitor its internal state such that if it IS in an invalid state it doesn''t allow any state specific operations to succeed upon it until it is fixed or destroyed.

You are right in that the class should never be sitting in an intermediate (unstable) state but it is VERY common for classes to be sitting in "uninitialized" state, or "invalid" state. These would be actual states. Sometimes lifetime constraints require that classes be built PRIOR to full initialization and that it remain constructed and alive after it has become invalid, for data/error gathering purposes.

Share this post


Link to post
Share on other sites
centralizing all initialization (and deinitialization) into separate functions is good. if u add init(), u can still call it in the constructor and validate the return values IN the constructor.. do watever u want with it.

i think this way is good coz u decouple the automation of object creation and destruction. this way u can not only initialize an object upon creation, u can FORCEfully deinit() and then init() again to get a ''fresh'' start.

but opinions may vary

Share this post


Link to post
Share on other sites
quote:
Original post by RandomTask
I think I''m going to disagree with you on some of this. It is never the USED class''s responsibility to fully prevent errors from occuring within itself.

Right. Which is why you would throw an exception. Having a two-phase creation-initialisation process forces client code to look like this:

  
int do_stuff()
{
C c;
if(c.ok())
{
// ... continue processing ...

}
else
{
return ERROR_SOMETHING_OR_OTHER;
}
}

int do_other_stuff()
{
int ret = do_stuff();
if(ret != ERROR_SOMETHING_OR_OTHER)
{
// ... continue processing ...

}
else
{
return ret;
}
}

All of a sudden, you are having to manually propagate error conditions all the way through the stack unwinding, which means you are writing tons of code just to do that, and you are also using up the return value of the functions, which could be used for something functional. Exceptions were invented to solve this very problem.
quote:

This is an unrealistic constraint. It is always the USING class''s responsibility to verify that every function call it executed succeeded and is valid.

Not so. Errors should be propagated to a context where they can be dealt with sensibly. Dealing with an error generally should involve reverting to the previously stable application state, and setting up the context for the next attempt at advancing the state (perhaps by asking the user what to do next).
quote:

It IS the USED classes responsibility to monitor its internal state such that if it IS in an invalid state it doesn''t allow any state specific operations to succeed upon it until it is fixed or destroyed.

You always need a core of classes which can be guaranteed to never be in an invalid state. These classes provide the core axioms of the system and provide some assurances of correctness. This is the basis of the C++ strong exception guarantee. The more units of modularity which can guarantee valid state, the easier it becomes to reason about program correctness (in terms of deciding how to revert to a previous stable state). Having an unnecessary two-phase creation process is a willing subversion of these principles.
quote:

You are right in that the class should never be sitting in an intermediate (unstable) state but it is VERY common for classes to be sitting in "uninitialized" state, or "invalid" state. These would be actual states.

They would mostly be *artificial* states. The only good reason I can think of for allowing an initialisation function is to simulate reinitialisation of object state.

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!