views:

357

answers:

5

I want to make a global vector of my own object class called "Person". However, the compiler says that

    error C2039: '{dtor}' : is not a member of 'System::IDisposable'
1>        c:\windows\microsoft.net\framework\v2.0.50727\mscorlib.dll : see declaration of 'System::IDisposable'

So I looked up how to implement IDisposable (which I now know is used primarily for unmanaged resources) but still can't seem to implement it with the following:

ref class Globals : System::IDisposable
{  
public: 
  static cliext::vector<Person^> person_data = gcnew cliext::vector<Person^>;
    void Dispose()
    {
         delete person_data;
    }
}; 

The 2 errors I get are:

error C2605: 'Dispose' : this method is reserved within a managed class
1>        did you intend to define a destructor?
error C3766: 'Globals' must provide an implementation for the interface method 'void System::IDisposable::Dispose(void)'
1>        c:\windows\microsoft.net\framework\v2.0.50727\mscorlib.dll : see declaration of 'System::IDisposable::Dispose'

Any help would be greatly appreciated.

A: 

Use a destructor. In C++/CLI ~ClassName() is Dispose() and !ClassName() is equivalent to C#'s ~ClassName(). In your case:

ref class Globals : System::IDisposable
{  
public: 
    static cliext::vector<Person^> person_data = gcnew cliext::vector<Person^>;
    void ~Globals()
    {
        delete person_data;
    }
}; 
Robert Fraser
The compiler then says that a destructor cannot have a return type. Removing 'void' however makes the compiler unable to recognise the function as an implementation of IDisposable (since it's of the form void func(void) presumably?)
Dororo
A: 

use a finalizer as shown at http://www.codeproject.com/KB/mcpp/cppclidtors.aspx

Sheng Jiang 蒋晟
A: 

You don't have to explicitly derive from IDisposable. Following the MSDN doco, use the following pattern:

ref class Globals
{
public:
    static cliext::vector<Person^> person_data = gcnew cliext::vector<Person^>;
    !Globals() // finalizer
    {
        delete person_data;
    {
protected:
    ~Globals() // destructor calls finalizer
    {
        this->!Globals();
    }
};
mcdave
Thanks for your help, but I still get an error at:static cliext::vector<Person^> person_data = gcnew cliext::vector<Person^>;The compiler states that the destructor is not a member of IDisposable:1>error C2039: '{dtor}' : is not a member of 'System::IDisposable'1> c:\windows\microsoft.net\framework\v2.0.50727\mscorlib.dll : see declaration of 'System::IDisposable'Even after ensuring the Person class is indeed IDisposable, it still refuses to compile.
Dororo
The only way I can get it to compile is to remove the 'static' keyword from person_data. As soon as you have a static member of type cliext::vector<T> you get that error -- I tried removing person_data and replacing it with cliext::vector<int> int_data = gcnew cliext::vector<int>; and still got the same error! Its beyond my skills.
mcdave
you can't delete what's not a handle
Ben Voigt
A: 

From C++/CLI in Action The C++/CLI Dispose pattern has these rules (paraphrased):

  • If a class has a finalizer or a destructor the compiler generates Dispose(bool) that will call either the finalizer or destructor based on the bool value.
  • If it has just a d'tor (~type) then the compiler calls Dispose(true) so the d'tor is called.
  • If it has just a finalizer (!type) then the compiler calls Dispose(false) so the finalizer is called

Also for the second rule: The compiler will implement the IDisposable interface for you (by generating Dispose()). It then uses SuppressFinalize to make sure the finalizer isn't called.

I did this to your code and the only way I could get it to compile was to make person_data a instance member. The error i got when it was static was error C2039: '{dtor}' : is not a member of 'System::IDisposable' which doesn't make much sense.

Also, do you even need to delete the person_data vector since is a managed object? Maybe you do but I haven't used the cliext enough to say.

Edit Perhaps the first paragraph of this article has the answer (emphasis mine):

When you declare a member variable as static and when the application starts, the compiler creates a copy of that member. This member would be maintained by the compiler while the program is running. If you declare an instance of a class, like the above vehicle variable, the static member is not part of the object: the compiler creates and maintains the static member, whether you use it or not, whether you declare a class variable or not.

cmw
Thanks for your reply, I think that will indeed do the trick. No idea why that destructor error keeps coming up though.
Dororo
I can't seem to find any information about freeing static members in destructor or finalizers. Perhaps someone out there knows the answer and will share.
cmw
static members are initialized by the .cctor, not at application startup
Ben Voigt
A: 

You don't need to implement Dispose() yourself, either directly or via a destructor. The implicitly-generated destructor already destroys all member objects. The IDisposable interface will be added automatically, don't mention it explicitly.

Next, you need to make up your mind whether person_data is a handle (which has to be set to an instance created with gcnew) or member object semantics (like stack semantics, the constructor is automatically called by the constructor of the parent object, the destructor called automatically when the lifetime of the parent object ends, and you use "." instead of "->" to access members).

Also, are you sure you want one copy of person_data shared between all instances of "Globals", but destroyed by the first instance to be disposed, leaving any other instances holding an invalid reference (reference to disposed object)? It looks like you're trying to use a Singleton anti-pattern here, is that correct?

Ben Voigt