Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. Managed C++/CLI
  4. What makes a class IDisposable?

What makes a class IDisposable?

Scheduled Pinned Locked Moved Managed C++/CLI
csharpc++visual-studioquestion
32 Posts 6 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    mid 5741
    wrote on last edited by
    #1

    In a VS2005 SP1 C++/CLI project I have a class declared like:

    ref class CallbackProxy
    {
    /* members and such */
    };

    This class is a private member of another C++/CLI class, AsioDevice. I've turned on code analysis in Visual Studio, and I get this:

    warning: CA2213 : Microsoft.Usage : 'AsioLib.AsioDevice' contains field 'callbackProxy_' that is of IDisposable type: AsioLib.CallbackProxy. Change AsioLib.AsioDevice's Dispose method to call Dispose or Close on this field.

    How did my CallbackProxy class become IDisposable? None of its members are IDisposable.

    M 1 Reply Last reply
    0
    • M mid 5741

      In a VS2005 SP1 C++/CLI project I have a class declared like:

      ref class CallbackProxy
      {
      /* members and such */
      };

      This class is a private member of another C++/CLI class, AsioDevice. I've turned on code analysis in Visual Studio, and I get this:

      warning: CA2213 : Microsoft.Usage : 'AsioLib.AsioDevice' contains field 'callbackProxy_' that is of IDisposable type: AsioLib.CallbackProxy. Change AsioLib.AsioDevice's Dispose method to call Dispose or Close on this field.

      How did my CallbackProxy class become IDisposable? None of its members are IDisposable.

      M Offline
      M Offline
      Mark Salsbery
      wrote on last edited by
      #2

      Does CallbackProxy have a destructor?  If so, that's probably how it became IDisposable. See Destructors and Finalizers in Visual C++[^] for details. Mark

      Mark Salsbery Microsoft MVP - Visual C++ :java:

      M 1 Reply Last reply
      0
      • M Mark Salsbery

        Does CallbackProxy have a destructor?  If so, that's probably how it became IDisposable. See Destructors and Finalizers in Visual C++[^] for details. Mark

        Mark Salsbery Microsoft MVP - Visual C++ :java:

        M Offline
        M Offline
        mid 5741
        wrote on last edited by
        #3

        Yeah, it does. But that link doesn't really clarify things for me. In my class' ctor, I new a pointer to a native struct. In my class' dtor, I delete said pointer. If what I'm reading is correct, the dtor is not called when the reference to callbackProxy_ goes out of scope; I need to explicitly call delete on it. That just seems totally counterintuitive to using managed code. But what I'd really like is a auto_ptr<>-like class, which I found here: http://www.codeproject.com/managedcpp/CAutoNativePtr.asp

        L M 3 Replies Last reply
        0
        • M mid 5741

          Yeah, it does. But that link doesn't really clarify things for me. In my class' ctor, I new a pointer to a native struct. In my class' dtor, I delete said pointer. If what I'm reading is correct, the dtor is not called when the reference to callbackProxy_ goes out of scope; I need to explicitly call delete on it. That just seems totally counterintuitive to using managed code. But what I'd really like is a auto_ptr<>-like class, which I found here: http://www.codeproject.com/managedcpp/CAutoNativePtr.asp

          L Offline
          L Offline
          Luc Pattyn
          wrote on last edited by
          #4

          Hi Michael, I don't know how it is in C++, this is what I can tell you about C#: - structs are value types, they get allocated on the stack (in the stack frame of the method that defines them) or inside an object that holds them (similar to an int). You can "create" them with the new keyword, but that merely serves as a way to pass initial values. No one cares about destroying them, they disappear when the method returns. - class objects are reference types; you create (i.e. allocate and initialize) them with the new keyword (that would be gcnew in C++), and they get collected by the gc if no live objects are referencing them any more. - there is no such thing as a destructor, but you can have a class implement the IDisposable interface by providing a Dispose method and stating the interface explicitly. - There is no automatic addition of a Dispose method or IDisposable interface (as opposed to the article about C++). Hope this helps.

          Luc Pattyn [Forum Guidelines] [My Articles]


          this weeks tips: - make Visual display line numbers: Tools/Options/TextEditor/... - show exceptions with ToString() to see all information - before you ask a question here, search CodeProject, then Google


          M 1 Reply Last reply
          0
          • L Luc Pattyn

            Hi Michael, I don't know how it is in C++, this is what I can tell you about C#: - structs are value types, they get allocated on the stack (in the stack frame of the method that defines them) or inside an object that holds them (similar to an int). You can "create" them with the new keyword, but that merely serves as a way to pass initial values. No one cares about destroying them, they disappear when the method returns. - class objects are reference types; you create (i.e. allocate and initialize) them with the new keyword (that would be gcnew in C++), and they get collected by the gc if no live objects are referencing them any more. - there is no such thing as a destructor, but you can have a class implement the IDisposable interface by providing a Dispose method and stating the interface explicitly. - There is no automatic addition of a Dispose method or IDisposable interface (as opposed to the article about C++). Hope this helps.

            Luc Pattyn [Forum Guidelines] [My Articles]


            this weeks tips: - make Visual display line numbers: Tools/Options/TextEditor/... - show exceptions with ToString() to see all information - before you ask a question here, search CodeProject, then Google


            M Offline
            M Offline
            mid 5741
            wrote on last edited by
            #5

            In C++/CLI, both class and struct are reference types. They need to be explicitly modified using the value keyword to get a value type. My original problem is a design flaw. If I use a smart pointer, I don't need a destructor anymore and the problem goes away. -- modified at 11:11 Monday 13th August, 2007

            Luc Pattyn wrote:

            there is no such thing as a destructor

            Are you sure about that? I made this class:

            class Class1
            {
            public Class1()
            {
            Console.WriteLine( "Class1 constructed." );
            }

              ~Class1()
              {
                 Console.WriteLine( "Class1 destructed." );
              }
            

            }

            and I got "Class1 destructed." in my Output window. It was not deterministic, but it was called.

            I L 2 Replies Last reply
            0
            • M mid 5741

              Yeah, it does. But that link doesn't really clarify things for me. In my class' ctor, I new a pointer to a native struct. In my class' dtor, I delete said pointer. If what I'm reading is correct, the dtor is not called when the reference to callbackProxy_ goes out of scope; I need to explicitly call delete on it. That just seems totally counterintuitive to using managed code. But what I'd really like is a auto_ptr<>-like class, which I found here: http://www.codeproject.com/managedcpp/CAutoNativePtr.asp

              M Offline
              M Offline
              Mark Salsbery
              wrote on last edited by
              #6

              Michael Chapman wrote:

              That just seems totally counterintuitive to using managed code.

              Yes, but so is mixing native types and having destructors. The garbage collector will only cleanup managed objects if you don't specifically call a destructor. Since you don't need deterministic cleanup of your native object, the smart pointer is a good solution, since it provides the destructor/finalizer for you. Only if you needed deterministic cleanup of your native object would you need to implement a destructor and possibly a finalizer as shown in the article (although you do it implicitely with the smart pointer). Mark

              Mark Salsbery Microsoft MVP - Visual C++ :java:

              G 1 Reply Last reply
              0
              • M mid 5741

                Yeah, it does. But that link doesn't really clarify things for me. In my class' ctor, I new a pointer to a native struct. In my class' dtor, I delete said pointer. If what I'm reading is correct, the dtor is not called when the reference to callbackProxy_ goes out of scope; I need to explicitly call delete on it. That just seems totally counterintuitive to using managed code. But what I'd really like is a auto_ptr<>-like class, which I found here: http://www.codeproject.com/managedcpp/CAutoNativePtr.asp

                M Offline
                M Offline
                Mark Salsbery
                wrote on last edited by
                #7

                hmm...my Sunday morning reply made no sense - I'll take another crack at it. What I meant to say was... If you have unmanaged resources in a managed class then you'll need a way to free them, as always.  You could just cleanup your native resources in the destructor BUT the destructor won't be called unless you explicitly call it (using delete or calling it directly).  Having to do THAT would be counterintuitive :) To ensure your native object created with new gets deleted, you should implement a destructor AND a finalizer in its managed owner class - that's what Nish's smart pointer class does for you. That way you don't have to explicitly destruct your managed object.  If it is left for the GC to cleanup, the GC will call the finalizer (NOT the destructor!)...

                // Using this pattern will insure native/unmanaged objects are cleaned up in all cases

                ref class MyRefClass
                {
                int *NativeIntArray;
                public:
                   MyRefClass()  {NativeIntArray = new int[400];} // Constructor
                   ~MyRefClass()  {this->!MyRefClass();} // Destructor - cleanup managed objects / call finalizer
                   !MyRefClass()  {delete[] NativeIntArray;} // Finalizer - cleanup native objects
                }

                Cheers, Mark

                Mark Salsbery Microsoft MVP - Visual C++ :java:

                1 Reply Last reply
                0
                • M mid 5741

                  In C++/CLI, both class and struct are reference types. They need to be explicitly modified using the value keyword to get a value type. My original problem is a design flaw. If I use a smart pointer, I don't need a destructor anymore and the problem goes away. -- modified at 11:11 Monday 13th August, 2007

                  Luc Pattyn wrote:

                  there is no such thing as a destructor

                  Are you sure about that? I made this class:

                  class Class1
                  {
                  public Class1()
                  {
                  Console.WriteLine( "Class1 constructed." );
                  }

                    ~Class1()
                    {
                       Console.WriteLine( "Class1 destructed." );
                    }
                  

                  }

                  and I got "Class1 destructed." in my Output window. It was not deterministic, but it was called.

                  I Offline
                  I Offline
                  iddqd515
                  wrote on last edited by
                  #8

                  His post was C# specific, which is quite different from C++/CLI in some ways. In C# there is no destructor. The destructor syntax in C# ( ~Class1() ) is actually a finalizer. In C++/CLI ~Class1() maps to the Dispose() function from IDisposable giving you a form of deterministic destruction (though memory won't be reclaimed immediately you can count on resources being closed). The !Class() syntax maps to the finalizer in C++/CLI.

                  M 1 Reply Last reply
                  0
                  • I iddqd515

                    His post was C# specific, which is quite different from C++/CLI in some ways. In C# there is no destructor. The destructor syntax in C# ( ~Class1() ) is actually a finalizer. In C++/CLI ~Class1() maps to the Dispose() function from IDisposable giving you a form of deterministic destruction (though memory won't be reclaimed immediately you can count on resources being closed). The !Class() syntax maps to the finalizer in C++/CLI.

                    M Offline
                    M Offline
                    mid 5741
                    wrote on last edited by
                    #9

                    Class1 is a C# class. Take up the semantic argument with Microsoft for putting a "Destructors (C# Programming Guide)" page in the MSDN library.

                    L I 2 Replies Last reply
                    0
                    • M mid 5741

                      Class1 is a C# class. Take up the semantic argument with Microsoft for putting a "Destructors (C# Programming Guide)" page in the MSDN library.

                      L Offline
                      L Offline
                      led mike
                      wrote on last edited by
                      #10

                      semantics and documentation arguments aside, did your question get answered?

                      M 1 Reply Last reply
                      0
                      • M mid 5741

                        Class1 is a C# class. Take up the semantic argument with Microsoft for putting a "Destructors (C# Programming Guide)" page in the MSDN library.

                        I Offline
                        I Offline
                        iddqd515
                        wrote on last edited by
                        #11

                        oh right, wasn't paying close enough attention. And yes MS semantics are horribly confusing. In that case, the C# ~Class1() is the finalizer. And by explicitly defining one you ensure that it is called by the garbage collector before the memory for an instance of the class is reclaimed. So although you're printing 'destructed' its actually the garbage collector calling the finalizer before memory is reclaimed. Its not a destructor that runs when the variable goes out of scope as you would get if it was a C++/CLI ref class with ~Class1() defined. And unlike destruction, finalization is nondeterministic and incurs a high performance cost for both allocation and deallocation. So you never want to write one unless your class contains unmanaged resources that won't be cleaned up by the garbage collector. In that case the finalizer will ensure the unmanaged stuff is cleaned up even if someone forgets to call delete or Dispose.

                        M 1 Reply Last reply
                        0
                        • I iddqd515

                          oh right, wasn't paying close enough attention. And yes MS semantics are horribly confusing. In that case, the C# ~Class1() is the finalizer. And by explicitly defining one you ensure that it is called by the garbage collector before the memory for an instance of the class is reclaimed. So although you're printing 'destructed' its actually the garbage collector calling the finalizer before memory is reclaimed. Its not a destructor that runs when the variable goes out of scope as you would get if it was a C++/CLI ref class with ~Class1() defined. And unlike destruction, finalization is nondeterministic and incurs a high performance cost for both allocation and deallocation. So you never want to write one unless your class contains unmanaged resources that won't be cleaned up by the garbage collector. In that case the finalizer will ensure the unmanaged stuff is cleaned up even if someone forgets to call delete or Dispose.

                          M Offline
                          M Offline
                          mid 5741
                          wrote on last edited by
                          #12

                          I don't want to argue, but you're not being specific enough. A C# destructor is more than syntactic sugar. The code within it will be called and then an implicit call is made to Finalize(). I'm not disputing or judging what actually occurs, I'm just pointing out that "C# destructors do not exist" is not a true statement. And I'm certainly not advocating that every C# class define a destructor. I'm glad I made my original mistake in assuming that C++/CLI ctor/dtor behavior is the same as C++ ctor/dtor behavior because it cleared things up after clouding them for awhile.

                          I 1 Reply Last reply
                          0
                          • L led mike

                            semantics and documentation arguments aside, did your question get answered?

                            M Offline
                            M Offline
                            mid 5741
                            wrote on last edited by
                            #13

                            The second post in this thread answered the original question. Thanks, Mark.

                            1 Reply Last reply
                            0
                            • M mid 5741

                              In C++/CLI, both class and struct are reference types. They need to be explicitly modified using the value keyword to get a value type. My original problem is a design flaw. If I use a smart pointer, I don't need a destructor anymore and the problem goes away. -- modified at 11:11 Monday 13th August, 2007

                              Luc Pattyn wrote:

                              there is no such thing as a destructor

                              Are you sure about that? I made this class:

                              class Class1
                              {
                              public Class1()
                              {
                              Console.WriteLine( "Class1 constructed." );
                              }

                                ~Class1()
                                {
                                   Console.WriteLine( "Class1 destructed." );
                                }
                              

                              }

                              and I got "Class1 destructed." in my Output window. It was not deterministic, but it was called.

                              L Offline
                              L Offline
                              Luc Pattyn
                              wrote on last edited by
                              #14

                              Yes indeed, there is a destructor-like syntax, but it is actually called a finalizer; it is a bit confusing if you ask me. And as you said it has undeterministic behavior: It gets executed by the gc when it decides to collect the object. :)

                              Luc Pattyn [Forum Guidelines] [My Articles]


                              this weeks tips: - make Visual display line numbers: Tools/Options/TextEditor/... - show exceptions with ToString() to see all information - before you ask a question here, search CodeProject, then Google


                              1 Reply Last reply
                              0
                              • M mid 5741

                                I don't want to argue, but you're not being specific enough. A C# destructor is more than syntactic sugar. The code within it will be called and then an implicit call is made to Finalize(). I'm not disputing or judging what actually occurs, I'm just pointing out that "C# destructors do not exist" is not a true statement. And I'm certainly not advocating that every C# class define a destructor. I'm glad I made my original mistake in assuming that C++/CLI ctor/dtor behavior is the same as C++ ctor/dtor behavior because it cleared things up after clouding them for awhile.

                                I Offline
                                I Offline
                                iddqd515
                                wrote on last edited by
                                #15

                                That's just it though, it is syntactic sugar. When you write ~Class1() in C# you've got a finalizer. It's not doing something then calling Finalize() I don't believe. Internally the compiler synthesizes that to a call to Dispose(false) which is invoked by the garbage collector right before the memory is reclaimed nondeterministically. By contrast, a destructor in C++/CLI is synthesized to Dispose() { Dispose(true); GC::SuppressFinalize(); } While a call to !Class1() in C++/CLI (the finalizer) results in a call to Dispose(false). The ~Class1() is a finalizer, not a destructor. To call it a destructor is a complete misnomer and doesn't convey when or how its called. A destructor would be called automatically when the object goes out of scope (via a using block in C# or via stack semantics in C++/CLI) or when invoked specifically by Dispose(). You must not reference other finalizable objects in that finalizer and other similar rules for finalizers that aren't present in a destructor. In C++/CLI a class destructor is created by the compiler automatically and will clean up managed resources for you. A finalizer (~Class1() in C#) is not generated by the compiler. It only exists if you explicitly write one. Most important is the fact that the ~Class1() in C# is nondeterminitic which by its nature makes it not a destructor (since they're deterministic) and the performance penalty for creating a finalizer for a class (In C++/CLI you would incur this cost with !Class1() but ~Class1() would enable actual RAII destructor semantics like native C++). In C++/CLI you would write ~Class1() to properly handle the closing of resources in a way that can be done deterministically (when the object goes out of scope or a call to delete is made). This is a destructor. In C# when you write ~Class1() you're providing a way for the garbage collector to handle resource cleanup or unmanaged cleanup at the last second before memory reclamation in the case that the user failed to manually release it with Dispose or a using block. This is a finalizer. There is no destructor. You can't call delete. You have to write a Dispose method and/or use using blocks. The C++/CLI dtor/ctor behavior is semantically the same as native C++. Although the destructor in C++/CLI doesn't cause the memory to actually be reclaimed (as that's always the garbage collectors job for managed objects) it is invo

                                M 1 Reply Last reply
                                0
                                • I iddqd515

                                  That's just it though, it is syntactic sugar. When you write ~Class1() in C# you've got a finalizer. It's not doing something then calling Finalize() I don't believe. Internally the compiler synthesizes that to a call to Dispose(false) which is invoked by the garbage collector right before the memory is reclaimed nondeterministically. By contrast, a destructor in C++/CLI is synthesized to Dispose() { Dispose(true); GC::SuppressFinalize(); } While a call to !Class1() in C++/CLI (the finalizer) results in a call to Dispose(false). The ~Class1() is a finalizer, not a destructor. To call it a destructor is a complete misnomer and doesn't convey when or how its called. A destructor would be called automatically when the object goes out of scope (via a using block in C# or via stack semantics in C++/CLI) or when invoked specifically by Dispose(). You must not reference other finalizable objects in that finalizer and other similar rules for finalizers that aren't present in a destructor. In C++/CLI a class destructor is created by the compiler automatically and will clean up managed resources for you. A finalizer (~Class1() in C#) is not generated by the compiler. It only exists if you explicitly write one. Most important is the fact that the ~Class1() in C# is nondeterminitic which by its nature makes it not a destructor (since they're deterministic) and the performance penalty for creating a finalizer for a class (In C++/CLI you would incur this cost with !Class1() but ~Class1() would enable actual RAII destructor semantics like native C++). In C++/CLI you would write ~Class1() to properly handle the closing of resources in a way that can be done deterministically (when the object goes out of scope or a call to delete is made). This is a destructor. In C# when you write ~Class1() you're providing a way for the garbage collector to handle resource cleanup or unmanaged cleanup at the last second before memory reclamation in the case that the user failed to manually release it with Dispose or a using block. This is a finalizer. There is no destructor. You can't call delete. You have to write a Dispose method and/or use using blocks. The C++/CLI dtor/ctor behavior is semantically the same as native C++. Although the destructor in C++/CLI doesn't cause the memory to actually be reclaimed (as that's always the garbage collectors job for managed objects) it is invo

                                  M Offline
                                  M Offline
                                  mid 5741
                                  wrote on last edited by
                                  #16

                                  From the source code perspective, I have code in a destructor that gets called. That's it. I'm not concerned with what goes on underneath. We're debating semantics. When you write ~Class1() in C#, you've got a destructor, both in name and behavior. In native C++, one would expect a destructor to be called implicitly when an automatic variable goes out of scope. Such is not the case in C++/CLI. What's defined as a destructor in C++/CLI does not get called when an automatic variable goes out of scope. What's defined as a finalizer in C++/CLI gets called when an automatic variable goes out of scope. That, to me, is a big difference.

                                  I 1 Reply Last reply
                                  0
                                  • M mid 5741

                                    From the source code perspective, I have code in a destructor that gets called. That's it. I'm not concerned with what goes on underneath. We're debating semantics. When you write ~Class1() in C#, you've got a destructor, both in name and behavior. In native C++, one would expect a destructor to be called implicitly when an automatic variable goes out of scope. Such is not the case in C++/CLI. What's defined as a destructor in C++/CLI does not get called when an automatic variable goes out of scope. What's defined as a finalizer in C++/CLI gets called when an automatic variable goes out of scope. That, to me, is a big difference.

                                    I Offline
                                    I Offline
                                    iddqd515
                                    wrote on last edited by
                                    #17

                                    You seem to be confused. You have to be concerned with what goes on underneath or you won't understand how this works. When you write ~Class1() in C# you have a finalizer in behavior. The syntax is like a C++ destructor and this is confusing on Microsoft's part. Assume you have a C# class with ~Class1() defined. Now, whenever you instantiate an object of Class1 you incur a performance penalty simply because the finalizer exists. The Class1 instance must register in a Finalizable queue and an freachable queue when the GC does its business. ~Class1() (really a call to Dispose(false) ) will be invoked by the garbage collector every time an object of Class1 is about to be reclaimed. The simple existence of ~Class1() and the subsequent placement in the freachable queue can cause objects of Class1 to be promoted to another generation and not be collected by the GC when it really could be. Most importantly, you have no idea when ~Class1() will be called by the garbage collector. Its completely nondeterministic. This by its very nature means its not a destructor. The finalizer is there to let you code last minute cleanup of unmanaged resources (which the GC cannot work with) in case the user of your class did not properly call Dispose() on an instance of Class1 or use a using block. And like I said before, there's a huge number of restrictions for what you can do in a finalizer vs a destructor. Now assume we have Class1 in C++/CLI with ~Class1() defined. This will be called when an object of Class1 goes out of scope IF you declared that object with stack semantics (i.e., Class1 myClass1Object). If you dynamically allocate memory with gcnew then you must use delete to invoke the destructor deterministically. This is the same as what happens in native C++. The difference in C++/CLI is that the memory itself won't be immediately reclaimed immediately (as that's the GC's job and it works nondeterministically) but that's not an issue. It will be reclaimed when more memory is required. The important part is that the destructor (~Class1()) will always be invoked implicitly when the automatic variable goes out of scope. A C# class with ~Class1() defined does not function this way because in C# ~Class1() is a finalizer not a destructor. So in C++/CLI you put resource-release code in your destructor ~Class1() and then an automatic vari

                                    M M 2 Replies Last reply
                                    0
                                    • I iddqd515

                                      You seem to be confused. You have to be concerned with what goes on underneath or you won't understand how this works. When you write ~Class1() in C# you have a finalizer in behavior. The syntax is like a C++ destructor and this is confusing on Microsoft's part. Assume you have a C# class with ~Class1() defined. Now, whenever you instantiate an object of Class1 you incur a performance penalty simply because the finalizer exists. The Class1 instance must register in a Finalizable queue and an freachable queue when the GC does its business. ~Class1() (really a call to Dispose(false) ) will be invoked by the garbage collector every time an object of Class1 is about to be reclaimed. The simple existence of ~Class1() and the subsequent placement in the freachable queue can cause objects of Class1 to be promoted to another generation and not be collected by the GC when it really could be. Most importantly, you have no idea when ~Class1() will be called by the garbage collector. Its completely nondeterministic. This by its very nature means its not a destructor. The finalizer is there to let you code last minute cleanup of unmanaged resources (which the GC cannot work with) in case the user of your class did not properly call Dispose() on an instance of Class1 or use a using block. And like I said before, there's a huge number of restrictions for what you can do in a finalizer vs a destructor. Now assume we have Class1 in C++/CLI with ~Class1() defined. This will be called when an object of Class1 goes out of scope IF you declared that object with stack semantics (i.e., Class1 myClass1Object). If you dynamically allocate memory with gcnew then you must use delete to invoke the destructor deterministically. This is the same as what happens in native C++. The difference in C++/CLI is that the memory itself won't be immediately reclaimed immediately (as that's the GC's job and it works nondeterministically) but that's not an issue. It will be reclaimed when more memory is required. The important part is that the destructor (~Class1()) will always be invoked implicitly when the automatic variable goes out of scope. A C# class with ~Class1() defined does not function this way because in C# ~Class1() is a finalizer not a destructor. So in C++/CLI you put resource-release code in your destructor ~Class1() and then an automatic vari

                                      M Offline
                                      M Offline
                                      Mark Salsbery
                                      wrote on last edited by
                                      #18

                                      I may be reading your comments wrong, but did you state a C++ ref class destructor is a finalizer? That's not the case.  The destructor maps to Dispose() and a finalizer must be explicitly added. Destructors do not get called if you allocate an object on the managed heap and never explicitly delete it.  The finalizer, however will be called when the handle no longer has any references to it and the GC gets around to cleaning it up.  That's why native objects should be freed in a finalizer, not a destructor (although the destructor should call the finalizer - the compiler takes care of SuppressFinalize).  Having to explicitly delete objects would be counterintuitive, as Michael originally stated.  Being able to (deterministically) using the familiar C++ syntax, however, is a nice, powerful feature. Note I'm only referring to C++ - I'll make no comments about C# except for the related Dispose/Finalize pattern of CLR. :) Cheers, Mark

                                      Mark Salsbery Microsoft MVP - Visual C++ :java:

                                      I 1 Reply Last reply
                                      0
                                      • I iddqd515

                                        You seem to be confused. You have to be concerned with what goes on underneath or you won't understand how this works. When you write ~Class1() in C# you have a finalizer in behavior. The syntax is like a C++ destructor and this is confusing on Microsoft's part. Assume you have a C# class with ~Class1() defined. Now, whenever you instantiate an object of Class1 you incur a performance penalty simply because the finalizer exists. The Class1 instance must register in a Finalizable queue and an freachable queue when the GC does its business. ~Class1() (really a call to Dispose(false) ) will be invoked by the garbage collector every time an object of Class1 is about to be reclaimed. The simple existence of ~Class1() and the subsequent placement in the freachable queue can cause objects of Class1 to be promoted to another generation and not be collected by the GC when it really could be. Most importantly, you have no idea when ~Class1() will be called by the garbage collector. Its completely nondeterministic. This by its very nature means its not a destructor. The finalizer is there to let you code last minute cleanup of unmanaged resources (which the GC cannot work with) in case the user of your class did not properly call Dispose() on an instance of Class1 or use a using block. And like I said before, there's a huge number of restrictions for what you can do in a finalizer vs a destructor. Now assume we have Class1 in C++/CLI with ~Class1() defined. This will be called when an object of Class1 goes out of scope IF you declared that object with stack semantics (i.e., Class1 myClass1Object). If you dynamically allocate memory with gcnew then you must use delete to invoke the destructor deterministically. This is the same as what happens in native C++. The difference in C++/CLI is that the memory itself won't be immediately reclaimed immediately (as that's the GC's job and it works nondeterministically) but that's not an issue. It will be reclaimed when more memory is required. The important part is that the destructor (~Class1()) will always be invoked implicitly when the automatic variable goes out of scope. A C# class with ~Class1() defined does not function this way because in C# ~Class1() is a finalizer not a destructor. So in C++/CLI you put resource-release code in your destructor ~Class1() and then an automatic vari

                                        M Offline
                                        M Offline
                                        mid 5741
                                        wrote on last edited by
                                        #19

                                        Are you being purposefully daft? I understand what's going on; I'm arguing that "C# does not have destructors" is an untrue statement. I'm not repudiating the mechanics. Dispute this: The C# language specification allows for the definition of destructors for class types.

                                        I 1 Reply Last reply
                                        0
                                        • M Mark Salsbery

                                          I may be reading your comments wrong, but did you state a C++ ref class destructor is a finalizer? That's not the case.  The destructor maps to Dispose() and a finalizer must be explicitly added. Destructors do not get called if you allocate an object on the managed heap and never explicitly delete it.  The finalizer, however will be called when the handle no longer has any references to it and the GC gets around to cleaning it up.  That's why native objects should be freed in a finalizer, not a destructor (although the destructor should call the finalizer - the compiler takes care of SuppressFinalize).  Having to explicitly delete objects would be counterintuitive, as Michael originally stated.  Being able to (deterministically) using the familiar C++ syntax, however, is a nice, powerful feature. Note I'm only referring to C++ - I'll make no comments about C# except for the related Dispose/Finalize pattern of CLR. :) Cheers, Mark

                                          Mark Salsbery Microsoft MVP - Visual C++ :java:

                                          I Offline
                                          I Offline
                                          iddqd515
                                          wrote on last edited by
                                          #20

                                          I'm pretty sure we've said the same thing. However... You say destructors are not called on an object allocated on the managed heap which isn't strictly true. If you allocate it on the managed heap with gcnew then yes the destructor is never called if you don't manually call delete. However, if you instantiate the ref class object with stack semantics then the destructor is called implicitly when the object goes out of scope (even though underneath its still allocated on the managed heap like all ref class objects). This is the critical addition to C++/CLI (vs MC++) that allowed for RAII style coding like native C++. Michael was claiming this is not the case (as it is in native C++) and that the finalizer is what is called, which is not correct. The finalizer will be called eventually either way if you define one, but the way things work is obviously much different than what a destructor provides. The confusion is that in C# when you declare ~Class1() this is actually mapped to the finalizer (Dispose(false)) in the dispose pattern. C# has no concept of destructors like C++ or C++/CLI even though the semantics there look like you're declaring a destructor. In C++/CLI you accomplish the same thing by declaring !Class1() which more properly distinguishes the finalizer from the destructor. Then declaring ~Class1() in C++/CLI does a very different thing than ~Class1() in C#. That's why in C# you need to explicitly call Dispose() in a finally block or use a using block with things like FileWriter objects to ensure there is no resource leak. C++/CLI's destructor semantics provide the handy native C++ style, FileWriter fw; which will automatically be disposed of properly when it goes out of scope (deterministically).

                                          M 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups