Jump to content

  • Log In with Google      Sign In   
  • Create Account


Making destructors compatible with C#...


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
19 replies to this topic

#1 Raptisoft   Members   -  Reputation: 171

Like
0Likes
Like

Posted 19 September 2011 - 10:18 AM

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!

Sponsor:

#2 Antheus   Members   -  Reputation: 2389

Like
0Likes
Like

Posted 19 September 2011 - 10:29 AM

Managed languages aren't required to run garbage collector.

so if I'm going to say new int and delete(int)

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.

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?

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.

#3 rip-off   Moderators   -  Reputation: 7622

Like
0Likes
Like

Posted 19 September 2011 - 10:31 AM

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.

#4 ApochPiQ   Moderators   -  Reputation: 14103

Like
0Likes
Like

Posted 19 September 2011 - 11:22 AM

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.

#5 iMalc   Crossbones+   -  Reputation: 2250

Like
0Likes
Like

Posted 19 September 2011 - 01:17 PM

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.
"In order to understand recursion, you must first understand recursion."
My website dedicated to sorting algorithms

#6 Raptisoft   Members   -  Reputation: 171

Like
0Likes
Like

Posted 19 September 2011 - 02:23 PM

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?

#7 Zipster   Crossbones+   -  Reputation: 545

Like
0Likes
Like

Posted 19 September 2011 - 02:47 PM

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 :)

#8 Telastyn   Crossbones+   -  Reputation: 3712

Like
0Likes
Like

Posted 19 September 2011 - 05:14 PM

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


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

IDisposable is about as close as you're going to get,


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.

#9 Postie   Members   -  Reputation: 856

Like
0Likes
Like

Posted 19 September 2011 - 07:30 PM

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.
Currently working on an open world survival RPG - For info check out my Development blog: ByteWrangler

#10 Avictus   Members   -  Reputation: 122

Like
0Likes
Like

Posted 20 September 2011 - 09:56 PM

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.

#11 Raptisoft   Members   -  Reputation: 171

Like
0Likes
Like

Posted 21 September 2011 - 07:49 AM

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.


This is exactly what I would like to accomplish. In C++/C#, deleting one object, I would accomplish it like this:

//C++
#define Delete(Object) {Object->Destroy();delete Object;}
//C#
#define Delete(Object) {Object->Destroy();}

What I'm looking for is some way I can make delete [] work the same way.

My assumption is that I will have to take all my destructor code, and move it into a Destroy() function. Then what I need is a nice seamless way to invoke that destroy function that will be compatible with C++ and C#. I'm looking for a way to cover all my bases, because at some point in the head of coding, I will surely do something like initialize an array, and then go over to C#, days or weeks later, and say, crap... I forgot I wasn't supposed to initialize arrays.

Now, one way I could do it would be a for/next loop:

#define DeleteArray(Object) {for (int aCount=0;aCount<GetObjectCountSomehow;aCount++) {Object[aCount]->Destroy;}}

But given this:

Object *aObject=new Object[25];

...how do I get that 25 elsewhere to iterate through? Is there a good way? Aside from using sizeof(Object array)/sizeof(Object[0])? Because that would add the extra complexity of having to put the class type in the delete, and now we're starting to talk very verbose code.

And, in an IDEAL world, there would be some way to make my delete define work, even on this:

struct Thingie
{
   int a,b,c;
};

Thingie *aT=new Thingie;
Delete(aT);

...even though Thingie doesn't have a Destroy() function at all. I would like to accomplish this for simplicity and consistency... and I was wondering if there was some magic preprocessor way to say "if Destroy() is defined, call it, otherwise, don't." I realize this is probably impossible, but like I said, I've seen people accomplish some astounding stuff with preprocessor, so if everyone DID come up with a way, I'd like to know it!

#12 Telastyn   Crossbones+   -  Reputation: 3712

Like
0Likes
Like

Posted 21 September 2011 - 08:12 AM

You don't need to make delete[] work. Arrays are evil, seriously.

If you have a vector<shared_ptr<T>> in C++, where T has an empty destructor, you'll behave pretty much like C# Lists.

But seriously, give us a concrete example of what you're doing and we'll give you a concrete answer. Trying to guess how you're abusing destructors in C++ makes it difficult to formulate good advice.

#13 arbitus   Members   -  Reputation: 436

Like
0Likes
Like

Posted 21 September 2011 - 08:17 AM

Why are you using defines and attempting to mix C++ and C#?

These two should not coexist in the same file, much less should you attempt to interleave preprocessor keywords.

I think you need to define the problem more clearly, as I have no idea WHY you want to do what you are doing, much less why you are doing it the way you have shown (which has many obvious code smells).

#14 Raptisoft   Members   -  Reputation: 171

Like
0Likes
Like

Posted 21 September 2011 - 08:46 AM

I dunno why "why" has to come up in a tech question with a tech answer, but here goes:

I code in C++. I like C++. It can work on Windows, it can work on iOS, it can work on Linux, the only place it can't work is where Microsoft has decided thou shalt use C# and C# thou shalt use.

I use very vanilla C++. I'm not a trickster with it. Most of my C++ can actually go to Java, even, with minimal changes. The only exception being destructors, which as I said above, I use heavily.

I am trying to make my C++ delete my objects, while at the same time make it so that I can move the whole shebang over to C# if I should need to. I am working toward future compatibility. I am not using C# at this time.

I am trying to give myself a consistent workaround, that I'll call all the time, to delete objects, which won't actually delete them on a managed language, but WILL invoke a "Destroy()" function that I can do housekeeping that I'd normally do in a destructor. I want this set up so I can use it fairly consistently in C++ and C# (small exceptions would be fine).

For my own sanity, I want it compatible with arrays and other stuff, so that I have margin to be sloppy.

Now, I know the Array[] delete is possible... I have a solution above, but was wondering if a better one exists. The "call Destroy()" function thing I want is probably *not* possible, but I'm asking on the chance that someone has ever accomplished that.

On the philosophy of programming: I know "change everything you're doing and do it my way" is always an option. But I am looking for a way to not "change everything I'm doing."

#15 Telastyn   Crossbones+   -  Reputation: 3712

Like
1Likes
Like

Posted 21 September 2011 - 09:23 AM

I dunno why "why" has to come up in a tech question with a tech answer,


Because you're doing things that will cause you grief in the future. We're asking 'why' because occasionally that grief is worthwhile to solve a difficult problem or to stop more grief that alternatives would cause you.

In this case though, it just seems as though you're purposefully harming your project due to ignorance, stubbornness, and/or absurd requirements. There is no good tech answer. Porting things is more than changing syntax around. C++ idioms don't translate to C#. C# idioms don't translate to C++. Doing icky things to support something you might want to do in the future is a classic pitfall to avoid.

#16 Raptisoft   Members   -  Reputation: 171

Like
-1Likes
Like

Posted 21 September 2011 - 09:28 AM

Porting things is more than changing syntax around.


I've been porting things for years and years. I've been coding since magnetic tape. There is no call for this.

Did you see this?

Most of my C++ can actually go to Java


If I asked you how to render a triangle in OpenGL, would you tell me a DirectX command, or give me an explanation of the virtues of triangle strips vs. triangle lists? There's a specific job I want to do, and a #define Delete will not cause me problems in the future, because if it does, I change the define. I am an agile programmer and am simply looking for a technical solution to a specific problem.

#17 Telastyn   Crossbones+   -  Reputation: 3712

Like
0Likes
Like

Posted 21 September 2011 - 09:34 AM

Most of my C++ can actually go to Java


Yes, I saw this. That's primarily what made me conclude that you have no idea how to port software (or write C++, one or the other)

Best of luck to you, I'll butt out and let others try to help.

#18 phantom   Moderators   -  Reputation: 6654

Like
0Likes
Like

Posted 21 September 2011 - 09:55 AM

The problem is there is no real easy technical answer to The Problem because C++ and C# operate under fundimentally different memory models. The best you have, for compatibility, is the IDisposible interface to get some of the functionality back.

A concrete example might give concrete solutions, however none are likely to be language agnostic (as you seem to want) or do able via pre-processor hackery as they are likely to require extra levels of abstraction and 'manager' type classes to enable controlled clean up and release in keeping with the semantics of the language in question.

The simple fact is you do not write C# code like you write C++ code; doing so is just going to lead to shitty C# code and, more than likely, shitty C# performance.

#19 Antheus   Members   -  Reputation: 2389

Like
0Likes
Like

Posted 21 September 2011 - 10:06 AM

Wait 1 year.
Download VS2011 (2012, whichever will launch).

Voila - your C++ code is now C# code. Or JS code. Or VB. Language simply doesn't matter anymore, if it's a library, it can be used from any language.

#20 arbitus   Members   -  Reputation: 436

Like
0Likes
Like

Posted 21 September 2011 - 10:25 AM

I dunno why "why" has to come up in a tech question with a tech answer, but here goes:


Because different languages and programming paradigms require you to approach problems differently. This is a tautology. What you have asked is how do to the same thing in two different languages without really explaining what that same thing is. You have claimed that you simply want to replicate object destruction, but it is clear that object destruction for you is more than just cleaning up resources, as you also seem to be handling reference counting in addition to resource destruction. Reference counting is usually not necessary in managed languages as once references to an object go out of scope, the resources that are used by the object are free to be released automatically. Of course there are exceptions to the rules, but that explains why people want more information concerning your approach and your needs.

I code in C++. I like C++. It can work on Windows, it can work on iOS, it can work on Linux, the only place it can't work is where Microsoft has decided thou shalt use C# and C# thou shalt use.


This is not even remotely true. The only time you need to use C# is when you want access to the .NET libraries, but this is hardly required for any project (although it is a valuable tool). And when working in .NET, you have access to multiple languages, not just C#. Perhaps much of your frustration is due to inexperience or a lack of education regarding the platform, and giving us more information concerning your problem will help us find the gaps in your knowledge to better arm you for the future?

I use very vanilla C++. I'm not a trickster with it. Most of my C++ can actually go to Java, even, with minimal changes. The only exception being destructors, which as I said above, I use heavily.


Here is the deal: Memory management in managed languages (Java, .NET, python, etc.) is a completely different paradigm from memory management in C++. Your issue seems to stem from a desire to try and equate the two. This is why we need more information: there is no easy answer to your problem because you are trying to do something that is fundamentally flawed.

I am trying to make my C++ delete my objects, while at the same time make it so that I can move the whole shebang over to C# if I should need to. I am working toward future compatibility. I am not using C# at this time.


In C++, you must manually delete heap allocated objects. In managed languages such as Java and C#, you do not need to manually delete heap allocated objects. Once all references to an object go out of scope, the memory allocated by that object is eligible to be "garbage collected" by the runtime. There is nothing the programmer needs to do to make this happen, other than ensure that they are no longer holding onto a reference to an object.

However, if your object is doing more than simply holding on to other managed objects (such as using an unmanaged resource) or requires additional logic at the time it is no longer needed by the application, then you must take additional steps. In C#, you have finalizers, which allow you to let go of unmanaged resources at the time the garbage collector decides to completely destroy your object. However, finalizers are non-deterministic, you never know when they will be invoked and you can never manually invoke them, because it is up to the garbage collector and the runtime. To compensate for this, .NET also uses the Dispose pattern. This allows for both deterministic deallocation of resources (by manually calling the dispose method or by implementing the using construct), and for non-deterministic resource deallocation, as if you forget to call dispose, it will be called by the garbage collector when it decides it can safely delete your object.

I am trying to give myself a consistent workaround, that I'll call all the time, to delete objects, which won't actually delete them on a managed language, but WILL invoke a "Destroy()" function that I can do housekeeping that I'd normally do in a destructor. I want this set up so I can use it fairly consistently in C++ and C# (small exceptions would be fine).


First of all, as we have already mentioned, trying to achieve parity between a managed and unmanaged language when it comes to memory management is a Bad Idea™. What I want to know is, what is the housekeeping you are doing in a destructor of your C++ objects that you need to do in C# that does not involve cleaning up allocated resources. This is the general purpose of destructors in C++, and if you are doing something else, you are not creating trivial destructors, so we need to know what makes your destructors so nontrivial. Your given example includes reference counting, but once again, we need to know what and why you are reference counting because this is often a process that is made unnecessary by managed languages.

For my own sanity, I want it compatible with arrays and other stuff, so that I have margin to be sloppy.

Now, I know the Array[] delete is possible... I have a solution above, but was wondering if a better one exists. The "call Destroy()" function thing I want is probably *not* possible, but I'm asking on the chance that someone has ever accomplished that.


You keep saying you want to delete objects, but at the same time you don't want to delete them. Can you see the fundamental disconnect here? What do you want Destroy() to do? Why do you want the object to continue living after calling Destroy()? Why can't you simply let the array fall out of scope or call Clear() on your List<>? What housekeeping do you need to do?

On the philosophy of programming: I know "change everything you're doing and do it my way" is always an option. But I am looking for a way to not "change everything I'm doing."


C++ and C# are miles apart as far as approach and paradigm. So are C++ and Java. There is no way you can #define your way into compatible solutions. If you are unwilling to adapt to the paradigms presented by your chosen tools, then all I can say is that you are Doing It Wrong™.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS