Jump to content
  • Advertisement
Sign in to follow this  
metsfan

One-Step vs Two-Step Initialization (C++)

This topic is 2162 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 am currently in the process of making some critical decisions for my game's code, and deciding on paradigms that I am going to stick with throughout the project and I just wanted to get some opinions on this subject. As far as I can tell, there are positives and negatives to both of these methods. I've done some research around the internet, and it seems to be a pretty split decision about which practice is better in general, so I put the question to all of you, which practice do you prefer and use in your games, and do you differ the practice used based on situation?

For those who are not familiar with this terminology:

One-Step Initialization - Constructor sets up the entire class and throws an exception on failure
Two-Step Initialization - Constructors simply allocates the object and all initialization is done through a separate method, which will usually have a return value of a boolean or some error code.

Thanks all.

Share this post


Link to post
Share on other sites
Advertisement
I prefer the same. Do as much as possible in the constructor and throw an exception if anything goes wrong. If you use return values to indicate failure, you can be sure to forget to check it every once in a while and you will get unpredictable behaviour sooner or later. If you forget to catch an exception, you get at least a well defined shutdown of your application.

Share this post


Link to post
Share on other sites
This isn't a one-size-fits-all situation. There are many platforms with sufficiently bad exception support that even enabling exceptions as a compiler options is a mistake. Even if you do enable exceptions in your project, there are certain operations that have a sufficiently high chance of failure that throwing an exception would be inappropriate. Examples include opening a file or a network connection. Consider the C++ standard library. With a std::fstream you can specify a file name as constructor argument, but if the file isn't opened, it doesn't throw an exception. In comparison, if any of the std::string constructors fail an exception is thrown.

Share this post


Link to post
Share on other sites
IMHO - when writing C++ code:
* Never use C++ exceptions (do use C SEH for crash report handling though).
* For C++ classes, use the C++ idiom of constructors/destructors instead of the C idiom of init/shutdown function.
* For C-style data structures, use the C idioms where applicable.
* Design as much code as possible so that failure simply isn't possible, then you don't need error handling code...
** If for some reason a constructor can fail (which usually is just a bad design), you do have the option of returning an error though an out param, or setting a 'zombie object' flag.

[Edit] Time travelling quote because I'm too lazy to add a new reply and start another "why C++ exceptions are great and/or evil" holy war thread -- there's enough of them already.
The specific domain here is game programming, so the bad exception support platforms aren't likely to be used.
Game consoles are the platforms that have bad C++ exception support. Microsoft/Sony tell you to disable exception support on their compilers in order to produce better binary code. Even x86/Win32 is pretty crap here, though x64 Windows is a lot better. Edited by Hodgman

Share this post


Link to post
Share on other sites

This isn't a one-size-fits-all situation. There are many platforms with sufficiently bad exception support that even enabling exceptions as a compiler options is a mistake. Even if you do enable exceptions in your project, there are certain operations that have a sufficiently high chance of failure that throwing an exception would be inappropriate. Examples include opening a file or a network connection. Consider the C++ standard library. With a std::fstream you can specify a file name as constructor argument, but if the file isn't opened, it doesn't throw an exception. In comparison, if any of the std::string constructors fail an exception is thrown.
The specific domain here is game programming, so the bad exception support platforms aren't likely to be used.

I don't agree with these examples of when not to use exceptions. If a critical resource, like a file is missing, that might be a good time to throw an exception.

Also a major consideration if an exception is appropriate is the cause of the error. If it is user error, then that's almost always not cause to use an exception. If it's a terminally missing resource, then throw one. Loading a missing save file -- don't throw. Corrupted save data - likely throw.

As an aside, one thing to watch out for is that you don't want to throw an exception in an exception handing routine. So don't make failure to log an error an exception, for example.

Share this post


Link to post
Share on other sites
i definately prefer 2 step, to me it makes code look nice, and it's more flexible on it's initialization and makes re-initializatioin even easier. And in c++ if you're old school you probably use memalloc,calloc, or what have you, which dont call constructors anyway.

Share this post


Link to post
Share on other sites

This isn't a one-size-fits-all situation. There are many platforms with sufficiently bad exception support that even enabling exceptions as a compiler options is a mistake.
For further elaboration. I've sometimes found myself to have the need to work with "non-trivial" ctors. Those kind of ctors that need object-specific behaviour by calling virtual functions.
Granted, I've mostly refactored those. But there are still a few cases in my current codebase where reliance on "virtual-based init" was the only possible way.
In this case, one-step init is just impossible.


The specific domain here is game programming,
Let me rephase this for you.
The specific domain here is jogging - where? city, offroad, mixed, gym. How? speed-oriented, long distances, cardio, weight loss...

Share this post


Link to post
Share on other sites

[quote name='SiCrane' timestamp='1342418425' post='4959464']
This isn't a one-size-fits-all situation. There are many platforms with sufficiently bad exception support that even enabling exceptions as a compiler options is a mistake.
For further elaboration. I've sometimes found myself to have the need to work with "non-trivial" ctors. Those kind of ctors that need object-specific behaviour by calling virtual functions.
Granted, I've mostly refactored those. But there are still a few cases in my current codebase where reliance on "virtual-based init" was the only possible way.
In this case, one-step init is just impossible.


The specific domain here is game programming,
Let me rephase this for you.
The specific domain here is jogging - where? city, offroad, mixed, gym. How? speed-oriented, long distances, cardio, weight loss...
[/quote]There are indeed case where One-Step Initialization is not a good idea or even possible, but they should be the exception, not the rule.

As to the other point, I don't think see what you're trying to tell me. Yes game programming is a broad domain, but what I said about it still holds.

Share this post


Link to post
Share on other sites

I would say one step, as much as possible. Exceptions make for cleaner code.



I prefer the same. Do as much as possible in the constructor and throw an exception if anything goes wrong. If you use return values to indicate failure, you can be sure to forget to check it every once in a while and you will get unpredictable behaviour sooner or later. If you forget to catch an exception, you get at least a well defined shutdown of your application.


What makes you think that you can't have your "initialize" function throw an exception? The concept of return codes is just one of the two ways to implement two step Initialization. If you prefer one step initialization, great! But why? If you believe exceptions make for cleaner code, and throwing an exception from an initialize function is perfectly valid and typical of C++ exception styled programming, then you haven't made an argument for either yet. Poorly constructed exception handling is no better than poorly constructed non-exception handling either, so saying you have a "well defined shutdown of your application" is not always true.

What SiCrane said about "This isn't a one-size-fits-all situation." is pretty much the main focus point that should be addressed. Looking past exceptions, which is only one of the main aspects to this issue, the cost of "creation, copy, and destruction" have to be kept in mind as well. How expensive is it to create, copy, or destroy your objects? Are your objects going to need pools for managing memory? It's just going to depend on a case by case basis, thus there is no one-size-fits-all solution.

Furthermore, why choose one or the other when both might be more appropriate? Resource Acquisition Is Initialization, RAII, is one such idiom where inherently it is one step initialization, but there are times when adding support for two step initialization can make for more flexible and simplified code. A specific example would be Win32 critical sections (whether you use them or not isn't important as much as understanding the justification). Rather than littering your code with Enter/LeaveCriticalSection calls, you can use RAII to greatly simplify the process. However, there might be times when you need the concept of RAII, but the implementation doesn't make logical sense. E.g., acquiring exclusive access to a CS, but not needing to maintain that access at all times (to prevent deadlocks), so allowing for two step initialization with manual cleanup code support helps keep things more simple/cheap than constructing/destructing new objects over and over.

It's typical in game development, and most other development, to make uses of 3rd party libraries at one point or another. Maybe it's a mysql++ connector wrapper, or a physics library, or an input or audio library, the list goes on. While a lot of people have a DIY mentality, it's important to understand that you can't simply reinvent the wheel for everything and will eventually have to resort to another person's code. A lot of these libraries might be setup to use exceptions, while some might not. In either case, you have to design your code around how the other components are setup.

This means, specifically to the OP, you should not be trying to "commit" to one style or another, especially in a language like C++. It's like saying you want to have dinner tonight, but don't want to eat a meal that would require the use of a fork. To each their own, of course, but it's certainly not a typical concern from that perspective to say the least.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

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

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!