静态工厂方法和静态对象内存泄漏

Static factory methods and static objects memory leaks

本文关键字:静态 内存 泄漏 对象 工厂 方法      更新时间:2023-10-16

我有一个带有静态工厂构造函数的类,该构造函数返回指向所创建对象的指针。

我必须将对象声明为命名空间中的静态对象,但我不知道如何正确删除它

class Foo
{
   public:
   Foo(int, int* );
   virtual ~Foo();
   static Foo* MyFooInitializer(int n )
   {
      int *p = new int[n];
      for (int i=0; i<n; i++)
         p[i]=i;
      Foo *ret = new Foo(n,p);
      delete p;
      return ret;
   }
   int someFooFunction(int a);
}

然后在我的命名空间中我有一个static inline函数

namespace MyNamespace
{
    static inline void  myfunction()
    {
        static Foo  *foo1 = Foo::MyFooInitializer(10); 
        int y = somevalue();
        int x = foo1->someFooFunction(int y);
    } 
}

我显然在这里有内存泄漏,因为该对象永远不会被删除。

重要的事实是,我需要将 foo1 声明为静态,因为一旦创建,它必须在所有程序期间是相同的对象,并且必须是唯一的(它跟踪一些变量)。

可能这是一个设计问题,但我不知道当我的程序退出或明确想要删除它以重新初始化它时如何删除它。

溶液:

我以这种方式修改了MyFooInitializer的主体:

   static Foo* MyFooInitializer(int n )
   {
      int *p = new int[n];
      for (int i=0; i<n; i++)
         p[i]=i;
      static Foo ret = Foo(n,p);
      delete[] p;
      return &ret;
   }

这使我可以在程序终止时正确释放所有内存。瓦尔格林德说所有的堆内存都被释放了!

这里不需要在堆上分配该 Foo:

static Foo* MyFooInitializer(int x) {
    static Foo some_foo(x);
    return &some_foo;
}

该代码中没有泄漏,当您的程序结束时,Foo将被销毁。

请注意,如果 MyFooInitializer 返回的指针实际上指向某个继承自 Foo 的类,那么您只需要对静态变量使用派生类型:

static Foo* MyFooInitializer(int x) {
    static SomeFooDerived some_foo(x);
    return &some_foo;
}

编辑:由于您提供了实际的函数体,我的答案是有效的。你会这样做:

static Foo* MyFooInitializer(int n ) {
   // Don't know what this p is, anyway...
   int *p = new int[n];
   for (int i=0; i<n; i++)
      p[i]=i;
   static Foo ret(n,g); // what is g?
   delete[] p; // smart pointer plx
   return &ret;
}

怎么样

static inline void  myfunction()
{
    static std::unique_ptr<Foo> foo1(Foo::MyFooInitializer(10));
    int y = somevalue();
    int x = foo1->someFooFunction(int y);
} 

如果你绝对需要动态创建 foo1,那么编写一个额外的类,并按值使其成为静态/全局的。然后使用它的析构函数删除对象。

class MasterControlClass
{
    public:
    Foo* foo1;
    MasterControl(){foo1 = NULL;}
    ~MasterControl(){delete(foo1), foo1 = NULL;}
};

static inline void myfunction()
{
     static MasterControlClass mcp;
     mcp.foo1 = Foo::MyFooInitializer(10); 
}

这样,当您的程序关闭时,mcp desctructor 将被调用并执行清理。如果要重新初始化,则必须在每次分配时删除foo1,只需添加

if(mcp.foo1)
{
    delete mcp.foo1;
    mcp.foo1= NULL;
}

或者更好的是,将其移至mcp方法。