为什么使用'new'导致内存泄漏?

我首先学习了C#,现在我开始使用C ++。 据我所知,C ++中的new操作符与C#中的操作符不同。

你能解释这个示例代码中内存泄漏的原因吗?

class A { ... };
struct B { ... };

A *object1 = new A();
B object2 = *(new B());

发生什么事

当你写T t; 你正在创建一个T类型的对象,并自动存储持续时间。 当它超出范围时它会自动清理。

当你写new T()你正在创建一个具有动态存储持续时间的T型对象。 它不会自动清理。

你需要传递一个指针来delete它以清理它:

然而,你的第二个例子更糟糕:你正在取消引用指针,并复制该对象。 这样你就失去了用new创建的对象的指针,所以即使你想要,也不能删除它!

你应该做什么

您应该更喜欢自动存储时间。 需要一个新的对象,只需写:

A a; // a new object of type A
B b; // a new object of type B

如果确实需要动态存储持续时间,请将指针存储到自动存储持续时间对象中,该对象会自动删除该对象。

template <typename T>
class automatic_pointer {
public:
    automatic_pointer(T* pointer) : pointer(pointer) {}

    // destructor: gets called upon cleanup
    // in this case, we want to use delete
    ~automatic_pointer() { delete pointer; }

    // emulate pointers!
    // with this we can write *p
    T& operator*() const { return *pointer; }
    // and with this we can write p->f()
    T* operator->() const { return pointer; }

private:
    T* pointer;

    // for this example, I'll just forbid copies
    // a smarter class could deal with this some other way
    automatic_pointer(automatic_pointer const&);
    automatic_pointer& operator=(automatic_pointer const&);
};

automatic_pointer<A> a(new A()); // acts like a pointer, but deletes automatically
automatic_pointer<B> b(new B()); // acts like a pointer, but deletes automatically

这是一个不常用的描述性名称RAII(资源获取初始化)的常见成语。 当您获取需要清理的资源时,可以将其保存在自动存储期限的对象中,因此您无需担心清理它。 这适用于任何资源,无论是内存,打开的文件,网络连接,或任何你喜欢的。

这个automatic_pointer事物已经以各种形式存在,我刚刚提供了一个例子。 标准库中存在一个非常类似的类,名为std::unique_ptr

还有一个名为auto_ptr的旧版本(pre-C ++ 11),但现在已弃用,因为它有一个奇怪的复制行为。

然后有一些更聪明的例子,比如std::shared_ptr ,它允许多个指针指向同一个对象,并且只在最后一个指针被销毁时清理它。


一步一步的解释:

// creates a new object on the heap:
new B()
// dereferences the object
*(new B())
// calls the copy constructor of B on the object
B object2 = *(new B());

所以最后,你在堆上有一个没有指针的对象,所以不可能删除。

另一个样本:

A *object1 = new A();

仅当您忘记delete分配的内存时才会发生内存泄漏:

delete object1;

在C ++中,存在自动存储的对象,堆栈中创建的对象以及具有动态存储的对象,这些对象将分配给new的堆,并且需要使用delete来释放自己。 (这大致都是)

认为你应该delete每个分配了new对象。

编辑

来想一想, object2不一定是内存泄漏。

下面的代码只是为了说明一点,这是一个坏主意,从来不喜欢这样的代码:

class B
{
public:
    B() {};   //default constructor
    B(const B& other) //copy constructor, this will be called
                      //on the line B object2 = *(new B())
    {
        delete &other;
    }
}

在这种情况下,由于other通过引用传递,它将成为new B()指向的确切对象。 因此,通过&other获得其地址并删除指针将释放内存。

但我无法强调这一点,不要这样做。 这仅仅是为了说明问题。


给定两个“对象”:

obj a;
obj b;

他们不会在记忆中占据相同的位置。 换句话说, &a != &b

将一个值赋给另一个不会改变它们的位置,但是它会改变它们的内容:

obj a;
obj b = a;
//a == b, but &a != &b

直观上,指针“对象”的工作方式相同:

obj *a;
obj *b = a;
//a == b, but &a != &b

现在,让我们看看你的例子:

A *object1 = new A();

这是将new A()的值object1 。 该值是一个指针,意思是object1 == new A() ,但是&object1 != &(new A()) 。 (请注意,这个例子不是有效的代码,它仅用于解释)

由于指针的值被保留,我们可以释放它指向的内存: delete object1; 由于我们的规则,这与delete (new A());行为相同delete (new A()); 没有泄漏。


对于第二个示例,您正在复制指向的对象。 该值是该对象的内容,而不是实际的指针。 和其他情况一样, &object2 != &*(new A())

B object2 = *(new B());

我们失去了指向分配内存的指针,因此我们无法释放它。 delete &object2; 看起来可能会起作用,但是因为&object2 != &*(new A()) ,它不等于delete (new A()) ,因此无效。

链接地址: http://www.djcxy.com/p/13759.html

上一篇: Why does the use of 'new' cause memory leaks?

下一篇: Malloc vs New for Primitives