To goto or not to goto?

Started by
92 comments, last by godplusplus 12 years, 8 months ago

If we use C++, lets write C++. Constructors and destructors and all.
...
I'd go even further and use std::unique_ptr, so you don't even have to write the destructor.
[/quote]
You should use std::unique_ptr anyway. In your current code, if Object[2..4] throws during construction the earlier objects will leak.

The alternative is:

MyClass::MyClass()
:
object1(0),
object2(0),
object3(0),
object4(0)
{
try
{
object1 = new Object1;
object2 = new Object2;
object3 = new Object3;
object4 = new Object4;
}
catch(...)
{
delete object4;
delete object3;
delete object2;
delete object1;
throw;
}
}

Ugh.
Advertisement

You should use std::unique_ptr anyway. In your current code, if Object[2..4] throws during construction the earlier objects will leak.

The alternative is:
...
Ugh.


You are right, I made silly incorrect example (with syntax errors) to criticize some other example. Ofcourse one should use RAII, which solves everything. One could even make the Object[1..4] to be members and not heap allocated, thus reducing the problem to:


MyClass::MyClass()
{
}
I think you'r example for goto is pretty bad. How can the allocation of those objects fail without throwing an exception?

http://stackoverflow.com/questions/550451/will-new-return-null-in-any-case

[quote name='Ftn' timestamp='1313058718' post='4847596']I think you'r example for goto is pretty bad. How can the allocation of those objects fail without throwing an exception?

http://stackoverflow...ull-in-any-case
[/quote]

Which boils down to "because your compiler is old and pre-standard" or "because you explicitely used new(nothrow)". That is relatively unlikely, at least compared to programmers still thinking that if their new ever fails, it will return 0 (heck, every day at work I'm staring at those pointless != NULL checks).
f@dzhttp://festini.device-zero.de

Which boils down to "because your compiler is old and pre-standard" or "because you explicitely used new(nothrow)". That is relatively unlikely, at least compared to programmers still thinking that if their new ever fails, it will return 0 (heck, every day at work I'm staring at those pointless != NULL checks).

What do they do if it is NULL? It would be a huge pain to handle allocation failure gracefully at every instance it could occur.

[quote name='Slavik81' timestamp='1313094939' post='4847904']
[quote name='Ftn' timestamp='1313058718' post='4847596']I think you'r example for goto is pretty bad. How can the allocation of those objects fail without throwing an exception?

http://stackoverflow...ull-in-any-case
[/quote]

Which boils down to "because your compiler is old and pre-standard" or "because you explicitely used new(nothrow)". That is relatively unlikely, at least compared to programmers still thinking that if their new ever fails, it will return 0 (heck, every day at work I'm staring at those pointless != NULL checks).
[/quote]
Those null checks however could well be valid if your new operator is overriden as the allocation at that point doesn't need to throw when it is not allocating. Most industry places actually don't use execeptions and hence rely on the fact that a valid allocation returns a null pointer.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

Which boils down to "because your compiler is old and pre-standard" or "because you explicitely used new(nothrow)". That is relatively unlikely, at least compared to programmers still thinking that if their new ever fails, it will return 0 (heck, every day at work I'm staring at those pointless != NULL checks).


[quote name='Slavik81']What do they do if it is NULL? It would be a huge pain to handle allocation failure gracefully at every instance it could occur.[/quote]

The only situation i can think of where new(std::nothrow) should be used is within exception objects (i.e. classes that are based on std::exception, and so on). This may also warrant the use of goto for garbage collection when encountering a == NULL result.
Latest project: Sideways Racing on the iPad

[quote name='Dragonion' timestamp='1312713595' post='4845734']
[quote name='szecs' timestamp='1312706072' post='4845715']I think the ones against goto always use the worst examples of gotos.

And for that reason, here is an example where I personally think it makes good sense to use goto statements (like a replacement for a small inline function):
[source]
static MyClass*MyClass::createInstance(void)
{
MyClass*inst=null;

if(!(inst=new MyClass()))
return null;
if(!(inst->object1=new Object1()))
goto FAILED;
if(!(inst->object2=new Object2()))
goto FAILED;
if(!(inst->object3=new Object3()))
goto FAILED;
if(!(inst->object4=new Object4()))
goto FAILED;

return inst;

FAILED:
{
delete inst->object1;
delete inst->object2;
delete inst->object3;
delete inst->object4;
delete inst;

return null;
}
}
[/source]
[/quote]

I think you'r example for goto is pretty bad. How can the allocation of those objects fail without throwing an exception?


static MyClass* MyClass::createInstance()
{
MyClass* inst = new MyClass();

if (inst)
{
bool failed = !(inst->object1 = new Object1());
if (!failed)
failed |= !(inst->object2 = new Object2());
if (!failed)
failed |= !(inst->object3 = new Object3());
if (!failed)
failed |= !(inst->object4 = new Object4());

if (failed)
{
delete inst->object1;
delete inst->object2;
delete inst->object3;
delete inst->object4;
delete inst;
inst = 0;
}
}

return inst;
}


If we use C++, lets write C++. Constructors and destructors and all.
[/quote]

You realize that your code is slower than the example using gotos and arguably less readable. You have an extra variable, 4 extra assignments, and an extra branch vs the goto code

edit: it appears to also fall into the trap of "The Phony Goto Debate" in the Code Complete article. tldr being that using a trivial piece of code you'd never put goto in anyway will more obviously paint goto in a bad light or vice versa the performance gains by using goto may be trivial as the example is trivial to begin with. It's a losing argument from both sides.

[quote name='Ftn' timestamp='1313058718' post='4847596']

static MyClass* MyClass::createInstance()
{
MyClass* inst = new MyClass();

if (inst)
{
bool failed = !(inst->object1 = new Object1());
if (!failed)
failed |= !(inst->object2 = new Object2());
if (!failed)
failed |= !(inst->object3 = new Object3());
if (!failed)
failed |= !(inst->object4 = new Object4());

if (failed)
{
delete inst->object1;
delete inst->object2;
delete inst->object3;
delete inst->object4;
delete inst;
inst = 0;
}
}

return inst;
}


If we use C++, lets write C++. Constructors and destructors and all.


You realize that your code is slower than the example using gotos and arguably less readable. You have an extra variable, 4 extra assignments, and an extra branch vs the goto code[/quote]

Ummmm... Premature optimization? While the code he proposed wasn't what I would call an improvement on the original code, you do realize that the most expensive operation would be the memory allocation, which is something you would try to avoid at all costs if possible in a time critical, tight loop, and the memory allocation should be the focus, if one is going to get into optimizing, and not on the more trivial things, right? The other argument you have (less readable) may be acceptable, however.

Anyway, I'm going to stop here because I don't want to get side tracked and have anyone start flaming or trolling. It was interesting to see everyone else's views on goto.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

Those null checks however could well be valid if your new operator is overriden as the allocation at that point doesn't need to throw when it is not allocating. Most industry places actually don't use execeptions and hence rely on the fact that a valid allocation returns a null pointer.


On projects like that I can see your point, but I assure you, nobody is overriding new or using an old compiler on this project (or actually does anything _useful_ as a result of this check), for example this kind of thing just makes you want to scream:


constructor()
{
if ( (subobjectA = new ObjectA) == NULL)
return;

if ( (subobjectB = new ObjectB) == NULL)
return;

...do more stuff
}
f@dzhttp://festini.device-zero.de

This topic is closed to new replies.

Advertisement