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

时间:2012-06-21 12:12:27

标签: c++ memory-leaks new-operator static-methods delete-operator

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

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

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声明为静态因为一旦创建它在所有程序中必须是同一个对象并且必须是唯一的(它会跟踪一些变量)。

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

SOLUTION:

我用这种方式修改了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;
   }

这允许我在程序终止时正确释放所有内存。 Valgrind说所有的堆内存都被释放了!

3 个答案:

答案 0 :(得分:4)

这里不需要在堆上分配那个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;
}

答案 1 :(得分:0)

怎么样

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

答案 2 :(得分:0)

如果您绝对需要动态创建foo1,那么请编写一个额外的类,并按值将其设置为static / global。然后使用它的析构函数删除对象。

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析构函数将被调用并进行清理。 如果你想重新初始化,那么你必须在每次分配时删除foo1,只需添加

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

甚至更好,将其移至mcp方法。