【问题标题】:C++, will this cause memory leak?C++,这会导致内存泄漏吗?
【发布时间】:2011-12-08 11:29:37
【问题描述】:

我知道我无法获得本地变量的引用。如:

int& func1()
{
    int i;
    i = 1;
    return i;
}

而且我知道这是正确的,但我必须在调用 func2() 后删除它

int* func2()
{
    int* p;
    p = new int;


       *p = 1;
        return p;
}

int main()
{
    int *p = func2();
    cout << *p << endl;
    delete p;
    return 0;
}

如果函数是这样的:

MyClass MyFunction()
{
    return new MyClass;
}

MyClass 的完整定义是:

class MyClass
{
public:
    MyClass() : num(1){}
    MyClass(MyClass*) : num(10){}
    int num;
};

这会导致内存泄漏吗?

我应该如何避免它? 该函数返回一个对象而不是指针,那么我该如何删除它呢?

PS:代码来自《Ruminations on C++》一书第 10 章。 原代码为:

Picture frame(const Pictrue& pic)
{
    // Picture has a constructor Picture(*P_Node)
    // Frame_Pic derives from P_Node
    // So the constructor Picture(*P_Node) will implicitly convert Frame_Pic to Picture.
    return new Frame_Pic(pic);
}

【问题讨论】:

  • MyClass MyFunction() { return new MyClass; } 不会编译,所以不:它不会泄漏内存!
  • @Johnsyweb 除非MyClass 有一个接受MyClass*(或其子类)的非显式构造函数。
  • @Motti:公平点。没有什么可以暗示它,但你可能是对的。
  • @Johnsyweb 你是对的(这就是我对你的评论投赞成票的原因),但永远不要说我没有挑剔。
  • @Johnsyweb 我忘了发布非显式构造函数。这次函数将符合要求。如何删除对象?

标签: c++ local-variables


【解决方案1】:
MyClass MyFunction() 
{     
return new MyClass; 
} 

这实际上是错误的。您正在返回一个指针。 所以应该是

MyClass* MyFunction()

如果你的功能是我上面提到的,如果你在使用后没有删除它。它会泄漏内存。

我应该如何避免它?该函数返回一个对象而不是指针,那么我该如何删除它呢?

这是一个编译错误。所以删除它的点不会上升

【讨论】:

    【解决方案2】:

    如果删除函数返回的指针,则不会发生内存泄漏。然而,这很容易出错,因为这意味着函数的每个客户端都必须知道它应该删除返回值。使用智能指针(shared_ptrunique_ptr 根据语义)会更好。

    Picture 示例也是如此。如果此对象正确管理其资源(即在析构函数中删除并具有良好的复制构造函数和operator=(按照Rule of Three),则不存在内存泄漏。

    【讨论】:

      【解决方案3】:

      使用具有指针构造函数的更新MyClass,我想你应该写:

      MyClass MyFunction() {
          MyClass *ptr = new MyClass;
          MyClass retval(ptr);
          delete ptr;   // the dynamically-allocated object isn't needed any more
          return retval;
      }
      

      这恰好是异常安全的,因为 MyClass 的构造函数不能抛出,但作为一般规则,你真的不应该在没有将结果直接放入智能指针的情况下调用 new

      MyClass MyFunction() {
          std::unique_ptr<MyClass>(new MyClass);
          return MyClass(ptr);
      }
      

      无论如何,这是一个相当荒谬的情况——如果你要按价值返回,根本没有理由打电话给new

      MyClass MyFunction() {
          MyClass tmpvalue;
          return &tmpvalue; // doesn't actually return the pointer, just an object
                            // constructed from it
      }
      

      由于指针构造函数甚至没有使用指针的值,所以你也可以这样写:

      MyClass MyFunction() {
          return 0; // returns an object constructed from a null pointer
      }
      

      在您从书中引用的原始代码中,我猜Picture 类有一个P_Node* 类型的数据成员,它存储指针值,并在其析构函数中对该指针调用delete .希望作者也对Picture的复制构造函数和复制赋值操作符做一些事情,以防止复制后的双重释放。我没有这本书,所以我无法检查我的猜测,但Picture 的代码应该显示它是如何完成的。

      [编辑:哦,那是 Koenig 和 Moo 的书之一。他们(超过)有能力,所以他们的Picture 类可以正确地处理资源。如果没有,那是因为这是故意犯错的例子。]

      【讨论】:

      • "返回 &tmpvalue;"我想你的意思是“return tmpvalue;”?
      • @Klaim:不,我没有。提问者想要返回使用指针构造函数构造的MyClass 的实例,因此默认构造函数具有num=10 而不是num=1。为什么这个类首先有这个荒谬的隐式构造函数我不知道,但显然提问者希望它被调用;-)
      【解决方案4】:

      这与您的“func2”示例相同。最后调用“框架”的人需要释放返回的图片。

      【讨论】:

        【解决方案5】:
        MyClass MyFunction()
        {
            return new MyClass;
        }
        

        不正确,因为 operator new 返回指向 MyClass 的指针,但您的函数返回 MyClass,而不是 MyClass*

        【讨论】:

          【解决方案6】:

          一个简单的检查是这样的:

          • 如果你在你的程序中使用N number of new,那么你必须使用N number of compatible1delete在您的程序中避免内存泄漏2

          那你是这样做的吗?是的,在第一种情况下(你正在做new int)你就是这样做的。没有内存泄漏。

          帖子的其余部分对我来说还不够清楚!


          1. 兼容 delete,我的意思是如果你以ptr = new T[M] 的形式使用new,那么兼容的delete 应该是delete []ptr 的形式。同样,delete ptrptr = new T 兼容。

          2。当然,如果你使用一些智能指针,那么你不必显式使用delete

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2010-10-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多