代码之家  ›  专栏  ›  技术社区  ›  tunnuz

这会导致C++中的内存泄漏吗?

  •  6
  • tunnuz  · 技术社区  · 17 年前

    我有一个C++内存管理的疑问,这显然是与引用和指针相关的。假设我有个班 Class 用一种方法 my_method :

    OtherClass& Class::my_method( ... ) {
        OtherClass* other_object = new OtherClass( ... );
        return *other_object;
    }
    

    同时,在附近的一段代码中:

    {
        Class m( ... );
        OtherClass n;
        n = m.my_method( ... );
    }
    

    所以,我知道有一个关于指针的一般规则(~“任何新的ed,必须是delete-d”),以避免内存泄漏。但基本上我是在引用我的堆分配对象,所以当n超出范围时,不应该调用OtherClass的析构函数来释放先前由其他对象指向的内存吗? 所以最后,真正的问题是:这会导致内存泄漏吗?

    谢谢。

    7 回复  |  直到 17 年前
        1
  •  6
  •   CB Bailey    17 年前

    很明显,您希望向调用者返回一个不需要保留任何引用的新对象。为此,最简单的方法是按值返回对象。

    OtherClass Class::my_method( ... ) {
        return OtherClass( ... );
    }
    

    然后在调用代码中,您可以这样构造新对象。

    {
        Class m( ... );
        OtherClass n( m.mymethod( ... ) );
    }
    

    这避免了返回临时引用或要求客户机到管理器删除返回的指针的任何顾虑。注意,这确实要求您的对象是可复制的,但对于按值返回时要避免的复制,这是一种合法且通常实现的优化。

    如果需要共享所有权或对象的生存期超出调用函数的范围,则只需要考虑共享指针或类似对象。在后一种情况下,您可以将此决定留给客户机,并且仍然按值返回。

    例如。

    {
        Class m( ... );
    
        // Trust me I know what I'm doing, I'll delete this object later...
        OtherClass* n = new OtherClass( m.mymethod( ... ) );
    }
    
        2
  •  12
  •   Adam Hawes    17 年前

    是的,这会导致内存泄漏。

    您要做的是,在RETURN语句中,取消对您创建的新对象的引用。编译器将调用赋值运算符作为返回的一部分,并将新对象的内容复制到调用方法中分配给它的对象。

    新对象将留在堆上,其指针将从堆栈中清除,从而造成内存泄漏。

    为什么不返回一个指针并用这种方式管理它呢?

        3
  •  5
  •   peterchen    17 年前

    调用析构函数和释放内存是C++中的两个不同的事情。

    delete 都调用析构函数并释放内存。 delete[] 调用析构函数获取分配的元素数,然后释放内存。

    当OtherClass超出范围时,将调用析构函数,但不会释放内存。


    作为一个建议,当您感觉到您已经完全理解C++中的指针时,查看智能指针,例如Boost智能指针,以减轻C++中的内存管理生命。(如见 article 这里介绍)
        4
  •  2
  •   Igor    17 年前

    您有两个其他类对象:

    一个是n,它在堆栈上创建,并在超出范围时成功删除。

    另一个是您在堆上创建的,在我的方法中。这个永远不会被删除,它会导致内存泄漏。

        5
  •  2
  •   Fredrik Jansson    17 年前

    如果可能,您可以考虑std::auto_ptr或boost/c0x shared_ptr来简化内存管理。

        6
  •  2
  •   PolyThinker    17 年前

    通常,当一个本地对象超出范围时,它的内存是 释放 因为它是在堆栈上分配的,堆栈会自动清理。因为对象是在堆上分配的,所以无法自动释放它。释放它的唯一方法是显式调用delete。

    我想你可以这样做:

    声明另一个类 DummyClass ,其中包含一个公共成员,该成员是指向 OtherClass 对象。在DummyClass的构造函数中,清除指向空值的指针。在函数中,声明类型为的对象 哑级 ,及其成员指针以创建另一个类型的对象 其他类 . 然后在的析构函数中 哑级 ,检查指针是否为空,否则删除。这样,当DummyClass对象超出范围时,您的对象将被自动清除。

        7
  •  2
  •   Christoph    17 年前

    如果您坚持堆栈分配,则不要使用 new 算子在 my_method() 并将引用传递给 n 取而代之的是

    void Class::my_method( OtherClass& other_object, ... ) {
        other_object.init( ... );
    }
    

    然后打电话 MyOy方法() 这样地:

    {
        Class m( ... );
        OtherClass n;
        m.my_method( n, ... );
    }
    

    为了让这种模式发挥作用, Class 必须实现某种 init() 方法,该方法允许在不调用构造函数的情况下正确初始化对象。