Jump to content
  • Advertisement
Sign in to follow this  
Raptisoft

Making destructors compatible with C#...

This topic is 2643 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 rely somewhat heavily on destructors in my programming. So the question I have here is how I can simulate this in garbage collection languages like C#. I program primarily in C++, but am looking for things I can do to make an eventual port to C# easier.

For instance, say I have a skeleton class that always keeps a variable updated somewhere...

class Skeleton
{
Skeleton() {gSkeletonCount++;}
~Skeleton() {gSkeletonCount--;}
};


Now, each "new Skeleton" increases gSkeletonCount, and each "delete Skeleton" decreases gSkeletonCount, and I always know how many of my skeletons are alive.

To convert this to C#-ish (or Java) compatibility, my initial inclination is to do this:

class Skeleton
{
Skeleton() {gSkeletonCount++;}
Destructor() {gSkeletonCount--;}
};

#ifdef NOAUTOGARBAGECOLLECTION
#define Delete(Object) {Object->Destructor();delete Object;}
#else
#define Delete(Object) {Object->Destructor();}
#endif


Simple enough!

BUT, and here's my question...
How could I make this compatible with other aspects of my code? For instance, I can't always count on having Destructor() defined... so if I'm going to say new int and delete(int), I will have to have a version of my defined "delete" that does NOT call Destructor(). That sort of sucks... are there any high-end preprocessor operations that could get around that?

And, I'm not even sure how I could wrangle this:


Skeleton *aSkellies=new Skeleton[25];
delete [] aSkellies;


...how could I make a define for delete [] that would actually call the Destructor() on each item?

Thanks for any help you can give!

Share this post


Link to post
Share on other sites
Advertisement
Managed languages aren't required to run garbage collector.

so if I'm going to say new int and delete(int)[/quote]
Managed languages don't have delete either.

The problem listed above is solved differently:class Skeleton {
List<Objects> skeletons;
};

// instead of having gSkeletonCount
Skeleton s;
s.skeletons.count();
Or, external resource management is discouraged, instead it's handled by container class.

I program primarily in C++, but am looking for things I can do to make an eventual port to C# easier.[/quote]
In short, nothing.

Programming models are fundamentally different. It will not make porting any easier and will only make C++ code a mess. There are simply too many requirements on C++ internals to make such port viable.


One brute force approach is:
- never define destructors
- never use references
- any pointer that is ever used anywhere may only ever be smart pointer (shared_ptr)
- never pass or store anything by value except for primitive types (int, float)

When writing such code the necessary idioms will emerge naturally, but it will also result in overly cumbersome and verbose C++ code, which will be considerably less efficient than equivalent managed code, so might as well dump C++. Such design also makes it impossible to use just about any third--party library, including STL or Boost.

are there any high-end preprocessor operations that could get around that?[/quote]
It's not syntax, the whole design is completely different.

It should also be noted that such trivial design has proven disastrous in Java and to lesser extent C# (due to huge pressure on GC and too much redundant resource management imposed by deep object graphs) which have adopted a different approach to resource management, a hybrid between extrinsic resource management and whatever language requires.

Share this post


Link to post
Share on other sites
Resource management is different enough that a 1:1 port between a manually memory managed, value-oriented language and a garbage collected, reference oriented language would be inadvisable.

One option is to always use explicit functions for deallocation, and use the destructor to assert that the explicit function has been called, but it is far from a complete solution.

Share this post


Link to post
Share on other sites
Honestly, your best bet is to give up on a copy/paste "port" and convert the program correctly - that is, by changing its design to suit the target language.

What you want to do is analogous to this:
  • You have a rocket
  • You have a car
  • You want a fast car
  • So you put the rocket inside the car
  • Now the rocket blasts through the windshield and destroys the interior of the car
  • You ask how to stop this from happening

    The answer, of course, is to stop trying to put a rocket inside a car. Just fly the rocket, or just drive the car.

Share this post


Link to post
Share on other sites

In short, nothing.

Programming models are fundamentally different. It will not make porting any easier and will only make C++ code a mess.
A very good point.
It's not worth compromising the quality of your C++ code... when you could just compromise on the quality of your C# code instead :P . I mean everywhere where objects would normally be destructed in the C++ code you could use a using statement in C#. I mean you could, not that it'd necessarily be a good idea.

Share this post


Link to post
Share on other sites
So, all philosophical dissertations and fatherly advice aside...

Does anyone know the mechanics of how I would accomplish either of the situations above?

I.E., 1, in the preprocessor, determine if the object I'm calling a Delete() macro on possesses a certain function that I can call (this one is probably impossible, but I have known some C++ gurus who have been able to come up with some astonishing preprocessor stuff)...

Or 2, when macroing delete [] into DeleteArray[] to actually step through each element and call a function?

Share this post


Link to post
Share on other sites

So, all philosophical dissertations and fatherly advice aside...

Does anyone know the mechanics of how I would accomplish either of the situations above?

I.E., 1, in the preprocessor, determine if the object I'm calling a Delete() macro on possesses a certain function that I can call (this one is probably impossible, but I have known some C++ gurus who have been able to come up with some astonishing preprocessor stuff)...

Or 2, when macroing delete [] into DeleteArray[] to actually step through each element and call a function?

IDisposable is about as close as you're going to get, but even then it basically amounts to calling a method whenever you want your object to be disposed, and it's typically reserved for handling unmanaged resources. This is what iMalc referred to when he mentioned the using statement, since you at least get a little syntactic assistance. Others have already given you their share of why this isn't a great idea, so I won't go there :)

Share this post


Link to post
Share on other sites

For instance, say I have a skeleton class that always keeps a variable updated somewhere...
[/quote]

That isn't really a good idea even in C++...


IDisposable is about as close as you're going to get,
[/quote]

Or you could have a separate method for termination that you need to call explicitly. That way you disentangle the logical 'killing' of an object from the memory management aspects of releasing the object's memory.

Share this post


Link to post
Share on other sites
You could create a manager class for the skeleton objects which contains the list of skeletons and use that to control the lifecycle of the skeleton objects. Then to delete them you call Manager.Delete(skeleton) and you can include any custom code you want that would normally be in the destructor of the skeleton class.

That should be doable in both c++ and c# without having to mess with either language's design philosophy.

I think if you try to solve the problem with some complicated preprocessor magic, you're creating more work for yourself down the line.

Share this post


Link to post
Share on other sites

So, all philosophical dissertations and fatherly advice aside...

Does anyone know the mechanics of how I would accomplish either of the situations above?

I.E., 1, in the preprocessor, determine if the object I'm calling a Delete() macro on possesses a certain function that I can call (this one is probably impossible, but I have known some C++ gurus who have been able to come up with some astonishing preprocessor stuff)...

Or 2, when macroing delete [] into DeleteArray[] to actually step through each element and call a function?


I may be misunderstanding your original question, but I would handle your specific scenario with a list. In your example, you seem to be mixing together object death with monster death. With a garbage collected language, object death isn't quite as important, so you're mostly concerned with the death of the monster.

I would just use the following:


List<Skeleton> skeletons = new List<Skeleton>();


If you want to get the skeleton count, use:

skeletons.Count;


To add a skeleton:

skeletons.Add(new Skeleton());


Delete a skeleton:

skeletons.Remove(skeleton);

Or:

skeletons.RemoveAt(index);


If you would like to remove all the skeletons in the list, use:

skeletons.Clear();


If there's something you want to do when a monster dies, you can create an OnDie() method or a Kill() method which your engine will call when a monster dies.
I apologize if I misunderstood your question.

Edit: Oh! I see now. You're looking for things you can do in your C++ code to make a possible future C# port easier. I apologize, but I'll leave my original response above just in case.

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.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!