Archived

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

neonfaktory

Cancelling a Constructor?

Recommended Posts

neonfaktory    134
I was just wondering if it is possible to ''cancel'' a constructor from inside after its been called. To clarify, or if you''re curious, I have particles in my game that get culled based on certain aspects. Some of these particles fill these "cull" aspects right from the start, so they are added, only to get culled with the culling function next game tick. Waste of resources and cycles, it seems. Now, one would suggest that since I have to have coordinates to call the constructor with, I can just run the checks manually before calling it and cancel the constructor before it even starts. Well, I may end up doing that, but it''s called from so many different places it would be a pain to find and add that to all of them. Expecially compared to if I could cancel the constructor. So, if anyone could help me on this, that''d be great .

Share this post


Link to post
Share on other sites
haro    502

class Sex
{
Sex( double x, double y, bool construct = true )
{
if( construct )
{
this->x = x;
this->y = y;
}
}
};

Share this post


Link to post
Share on other sites
haro    502
As another note, you shouldn't be constructing and deleting your particles. Set a flag in the particle class isAlive, if its true then when your particle engine is processing particles it just immediately skips that particle.

One easy way is to store your particles as an array ( since you generally know the max number of particles you will ever have, and you can insure no memory fragmentation of an array easily.. as compared to a dynamically sized linked list which is what I assume you're currently using ). Now, create a stack which you will use for insertion into the array. The stack will contain numbers of offsets into the array which aren't already used up. So each time you want to 'create' a particle you would do something like this:

particleList[ particleOffsets.pop() ].Instantiate( xlocation, ylocation, color, etc )

And when you wanted to 'delete' a particle you would simply do:

particleList[ 123 ].isAlive = false;
particleOffsets.push( 123 );

This is much more logical and efficient than continually allocating/deleting.


[edited by - haro on July 7, 2003 4:31:32 PM]

Share this post


Link to post
Share on other sites
neonfaktory    134
Haha, I knew someone would say something about the Particle method. But in all honesty, I don't know the max number of particles I could have. The Particle system handles the "pretty" particles, as well as the weapon particles, so it all depends on what is happening and who is shooting, etc. It would kinda suck if too many people were shooting and suddenly you couldnt anymore because the max particles were reached. I *do* like the method you suggested, though, only if I knew the max particle #.

About your constructor cancelling code, I have a few concerns.
First, I had mentioned I would rather not have to run the checks before the constructor, because that would be a huge pain to go through every piece of code that generates particles and add that.
Second, it seems kind of pointless because if you already know whether you are going to construct it or not (you have to determine "construct" bool before hand to send as a param), why would you call the constructor in the first place if you already tested whether or not you want to construct the object?
And finally, it seems as if the sex object is still created (not what I want), you just didn't copy over the parameters to the "sex" data members.

Perhaps I'm missing something? Oh, and don't take this wrong or anything - I appreciate any feedback and help I can get, thanks for the response .

[edited by - neonfaktory on July 8, 2003 12:29:14 PM]

Share this post


Link to post
Share on other sites
Fruny    1658
If you could cancel your constructor, what would happen to the variable you just created.

Particle p(x,y); // Ooooops we canceled the constructor
Particle* p = new Particle(x,y); // Idem


Throwing an exception would act as a ''cancel'', but you would have to add exception-handling code ... which doesn''t seem to be what you want.

One thing you *can* do though, is to write a function that does the test and returns a Particle* or 0 if culled, but then you would have to deal with null pointers ...




[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

Share this post


Link to post
Share on other sites
Mulligan    378
i think this is legal:


class Arrrrrg
{
Arg()
{
if( something )
{
delete this;
return;
}
}
}


although you would be better off creating one small function, such as "bool CreateParticle( data, data, data )" which has code that checks to see if the data is valid, and if it is, THEN initalizes the particle. All of the places in your code that create particles call this function instead of being in charge of creating the particles themselves. Its good coding practice to force a standard method on yourself because it will make sure that you always create them correctly.

[edited by - Mulligan on July 8, 2003 12:50:49 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
quote:
Original post by Mulligan
i think this is legal:



ha ha hah ho hee hee hee ha

good one.

what? you''re really serious? oh boy...

Share this post


Link to post
Share on other sites
stubble    158
As I guess you're interested in an answer to your question and not an alternative method - here is the closest I think you'll get.

(as I don't think throwing an exception is really valid for this scenario - the object isn't broken it just shouldn't have been constructed in the first place - you also face an unnecessary overhead as the object has already been partially constructed also exceptions have an overhead too).

Have a static factory method in your class that returns particles - or NULL. That way your culling condition is in one place and the instance is never created if it is already culled.

eg.

class Particle
{
public:

Particle* CreateParticle(float x, float y, float z, otherstuff..)
{
if(visible(x,y,z))
return new Particle(x,y,z, ...);

return NULL;
}

protected:
Particle(){};
};


[edited by - stubble on July 8, 2003 1:04:02 PM]

[edited by - stubble on July 8, 2003 1:18:00 PM]

Share this post


Link to post
Share on other sites
Kurioes    250
AFAIk the only way to "Cancel" a constructor is to throw an exception, as someone stated before.

Exception handling can make your life easier if you use it correctly (I''m not claiming I actually am using it the right way, I''m a n00b).

Particle:article()
{
initparticle();
if (cullparticle()) {
throw;
}
}

.. later on ..

Particle *p;
try {
p = new Particle();
particle_list->add(p); // won''t be reached if Particle:article throws
} catch ( ... ) { // not sure if this is correct
// well... no particle added... no harm done
}

This method is probably slow though.

Share this post


Link to post
Share on other sites
Sneftel    1788
quote:
Original post by Anonymous Poster
quote:
Original post by Mulligan
i think this is legal:



ha ha hah ho hee hee hee ha

good one.

what? you''re really serious? oh boy...

Another half-witted comment from a half-witted AP. "delete this" is completely legal syntax (though not what is required here).


How appropriate. You fight like a cow.

Share this post


Link to post
Share on other sites
neonfaktory    134
Hmm, looks like I have a few options laid out in front of me now. I really like what stubble mentioned, but I''m just curious as to how my program will react to trying to Link NULL objects to the Linked Lists and what not. Anyway, thanks a bunch for your help guys .

Share this post


Link to post
Share on other sites
Greatwolf    125
quote:
Original post by Mulligan
i think this is legal:


class Arrrrrg
{
Arg()
{
if( something )
{
delete this;
return;
}
}
}





Is this object committing suicide?





You fight like a dairy farmer.

Share this post


Link to post
Share on other sites
drslush    122
The particles have to be stored in an array, right? Otherwise how would they get updated. If they are in an array, they have to have some way to delete themselves eventually... since they control their own lifetime I assume. Just use the same method.

Not sure if the above paragraph makes any sense...

Share this post


Link to post
Share on other sites
Fruny    1658
Yup, objects can commit suicide. It is legal, so long as the object has been allocated with new. If it has been allocated on the stack, or with new[], you''re in for a heap of trouble (pun intended).

Arrrrrg myobject; <---- boom !
Arrrrrg* myarray = new Arrrrrg[100]; <---- boom too !

And anyway, it is a very bad idea to do that in a constructor.

Make the constructor private, and use an ordinary static member function to return a pointer as needed.


[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

Share this post


Link to post
Share on other sites
Auron    328
quote:
Is this object committing suicide?


No, it''s administering it''s own abortion, or forcing itself to miscarry... take your pick. It is deleting itself as it''s being created after all.

-Auron

Share this post


Link to post
Share on other sites
Greatwolf    125
I just read the FAQ a bit and was wondering if anyone can explain or elaborate a bit on the idea of using ''zombie'' objects? I''m not sure I quite get the explaination fully from the FAQ

Thanks

PS. wtf now we got zombies too? This just keeps getting wierder.





You fight like a dairy farmer.

Share this post


Link to post
Share on other sites
Cedric    158
To enable object zombiness, you must have a bool member called this_object_is_a_zombie, or this_object_is_dead. The users of the object can now check the state of this member. If it is true, the object is a zombie, and it should be killed. Or, it can be ignored, but if you don''t kill it right away, don''t be surprised if the zombie ends up causing a memory leak.

Cédric

Share this post


Link to post
Share on other sites
Greatwolf    125
ok I think I''m starting to see. So basically the the client that''s using this class checks the zombie flag before using/doing something to the instance. If it''s a zombie then the client would have to kill it using something like

delete pointertoZombie;

if the class was allocated using new. I can''t believe how silly this is getting. One of the reasons why I like programming

Ok one more question, what is a constructor failure like? For example, does it happen if the data members somehow fail to initialize proper or a ''new'' command returns null to pointer in the class etc.? The zombie flag is thus then use to signal that this object''s bad therefore don''t use it. Am I getting this idea right?





You fight like a dairy farmer.

Share this post


Link to post
Share on other sites
SabreMan    504
quote:
Original post by Sneftel
Another half-witted comment from a half-witted AP. "delete this" is completely legal syntax (though not what is required here).

True. Glaring typo aside, the syntax is legal, but the technique is immoral. What happens if the object is auto? What about references to the object - how do they know the object is `dead''?

Share this post


Link to post
Share on other sites
Sneftel    1788
quote:
Original post by SabreMan
quote:
Original post by Sneftel
Another half-witted comment from a half-witted AP. "delete this" is completely legal syntax (though not what is required here).

True. Glaring typo aside, the syntax is legal, but the technique is immoral. What happens if the object is auto? What about references to the object - how do they know the object is `dead''?

It''s a limited technique, but occasionally a useful one. The few times I''ve used it, the following things have been true:

1. The class is a private inner class of another class.
2. The class has a private constructor.

#1 means that you can avoid having references when you don''t want them, since you have full control over when stuff will be used. #2 means that you never have to worry about stack objects.


How appropriate. You fight like a cow.

Share this post


Link to post
Share on other sites
Cedric    158
quote:
Original post by Sneftel
It's a limited technique, but occasionally a useful one. The few times I've used it, the following things have been true:

1. The class is a private inner class of another class.
2. The class has a private constructor.

That's nice, but couldn't this be achieved with a static method?

class A{
bool zombie;
A(int x){zombie = (x<0);}
public:
static A* NewA(int x){
A* a = new A(x);
if(a->zombie){delete a; return NULL;} else return a;
}
};

An exception could even be thrown and caught internally (thus not requiring the user code to worry about it) instead of having the zombie variable.

Cédric

EDIT: I had made a very stupid error...

I've never done it myself, but this could possibly be done by overloading new.

[edited by - Cedric on July 9, 2003 12:29:15 PM]

Share this post


Link to post
Share on other sites
Sneftel    1788
You''re right, Cedric. The technique of "delete this" is not especially useful during construction, but rather, at the end of a lifetime. (I was speaking of the usefulness of the technique in general, not in this specific instance.)


How appropriate. You fight like a cow.

Share this post


Link to post
Share on other sites
thomas001    122

for(/*something*/) {
try {
particles.push_back(Particle(x,y));
} catch(CulledException&) {}
}

and

Particle::Particle(float x,float y) {
if(isCulled(x,y))
throw CulledException();
/* ... */
}





[edited by - thomas001 on July 9, 2003 12:42:12 PM]

Share this post


Link to post
Share on other sites
stubble    158
Another issue with aborting constructors with exceptions is that, under certain conditions, an object can be semi-constructed..

if you throw an error in the constructor of a bass class and catch it in the ctor of a subclass - but decide you can deal with it in the subclass without aborting the object then you end up with a partially created object - which can lead to no end of problems..

For example, and I know this is 1) very contrived 2) stupid - but it is still possible and I''ve seen programmers do it..


#include "stdafx.h"
#include <string.h>
#include <iostream>

class baseclass
{
public:
void setString(const char* const pStr)
{
if(pStr)
m_pString=strdup(pStr);
else
throw("Invalid String");
}

void printString()
{
std::cout << "String:" << m_pString << std::endl;
}

virtual ~baseclass()
{
if(m_pString)
delete[] m_pString;
}

private:

char* m_pString;
};

class subclass1 : public baseclass
{
public:
subclass1(const char* const pStr)
{
try{
setString(pStr);
}catch(...)
{
//ignore it - we can deal with - (bad..)

}
}
};

class errorclass : public subclass1
{
public:
errorclass()
:subclass1(NULL)
{
}
};


int main(int argc, char* argv[])
{
errorclass e; //e is never completely created


e.printString(); //bang.


return 0;
}


Share this post


Link to post
Share on other sites