C++ Ref类不是System::IDisposable的成员;实现IDisposable时遇到问题

3
我想创建一个全局的向量,其中包含我自己定义的对象类“Person”。然而,编译器提示说:
    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'

我查询了如何实现IDisposable(现在我知道主要用于非托管资源),但仍然似乎无法使用以下内容进行实现:

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

我收到的两个错误信息是:

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'
5个回答

3

您不必显式从IDisposable派生。根据MSDN文档,使用以下模式:

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();
    }
};

感谢您的帮助,但我仍然在以下代码行遇到错误:static cliext::vector<Person^> person_data = gcnew cliext::vector<Person^>;编译器报错,指出析构函数不是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'即使确保Person类确实是IDisposable,它仍然无法编译。 - Dororo
我能使它编译通过的唯一途径是从person_data中删除'static'关键字。一旦你有了类型为cliext :: vector <T>的静态成员,你就会遇到这个错误——我试着把person_data删除,并用gcnew cliext :: vector <int> int_data替换它,但仍然得到了同样的错误!这超出了我的能力范围。 - mcdave
你不能删除不是句柄的内容。 - Ben Voigt

1
使用析构函数。在C++/CLI中,~ClassName()等同于C#的~ClassName(),而Dispose()则等同于!ClassName()。对于您的情况:
ref class Globals : System::IDisposable
{  
public: 
    static cliext::vector<Person^> person_data = gcnew cliext::vector<Person^>;
    void ~Globals()
    {
        delete person_data;
    }
}; 

编译器随后指出析构函数不能有返回类型。然而,删除“void”会使编译器无法将该函数识别为IDisposable的实现(因为它的形式是void func(void)?) - Dororo

0

0

您不需要自己实现Dispose(),无论是直接实现还是通过析构函数。隐式生成的析构函数已经销毁了所有成员对象。IDisposable接口将自动添加,不需要显式提及。

接下来,您需要确定person_data是一个句柄(必须设置为使用gcnew创建的实例)还是成员对象语义(类似于堆栈语义,构造函数由父对象的构造函数自动调用,析构函数在父对象生命周期结束时自动调用,并且您使用“.”而不是“->”来访问成员)。

此外,您确定要在所有“Globals”实例之间共享一个person_data副本,但由首个被处理的实例销毁,从而使任何其他实例持有无效引用(引用已释放的对象)吗?这看起来像是想在这里使用Singleton反面模式,是吗?


-1

C++/CLI in Action 中,C++/CLI Dispose模式有以下规则(改述):

  • 如果一个类存在 finalizer 或 destructor,则编译器会生成Dispose(bool)函数,该函数将根据bool值调用 finalizer 或destructor。
  • 如果只有 d'tor (~type),则编译器将调用 Dispose(true) 以调用 d'tor。
  • 如果只有 finalizer(!type),则编译器将调用 Dispose(false) 以调用finalizer。

另外,对于第二条规则:编译器将为您实现IDisposable接口(通过生成Dispose())。然后使用SuppressFinalize确保不会调用finalizer。

我对您的代码进行了更改,唯一能够使其编译的方法是把person_data设置为实例成员。当它是静态的时候,我遇到的错误是error C2039: '{dtor}' : is not a member of 'System::IDisposable',这并没有太多意义。

另外,你是否需要删除person_data向量,因为它是一个托管对象?也许你需要,但我还没有使用cliext足够长的时间来说。

编辑或许这篇文章的第一段就有答案(重点在于我):

当你将成员变量声明为静态变量并且应用程序启动时,编译器会创建该成员的副本。这个成员将由编译器在程序运行时维护。如果你声明了一个类的实例,比如上面的vehicle变量,那么静态成员不是对象的一部分:编译器创建和维护静态成员,无论你是否使用它,无论你是否声明类变量。


谢谢您的回复,我认为那确实可以解决问题。不知道为什么会一直出现析构函数错误。 - Dororo
我似乎找不到有关在析构函数或终结器中释放静态成员的任何信息。也许有人知道答案并愿意分享。 - cmw
静态成员由 .cctor 初始化,而不是在应用程序启动时。 - Ben Voigt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接