Why does the use of 'new' cause memory leaks?

I learned C# first, and now I'm starting with C++. As I understand, operator new in C++ is not similar to the one in C#.

Can you explain the reason of the memory leak in this sample code?

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

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

What is happening

When you write T t; you're creating an object of type T with automatic storage duration. It will get cleaned up automatically when it goes out of scope.

When you write new T() you're creating an object of type T with dynamic storage duration. It won't get cleaned up automatically.

You need to pass a pointer to it to delete in order to clean it up:

However, your second example is worse: you're dereferencing the pointer, and making a copy of the object. This way you lose the pointer to the object created with new , so you can never delete it even if you wanted!

What you should do

You should prefer automatic storage duration. Need a new object, just write:

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

If you do need dynamic storage duration, store the pointer to the allocated object in an automatic storage duration object that deletes it automatically.

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

This is a common idiom that goes by the not-very-descriptive name RAII (Resource Acquisition Is Initialization). When you acquire a resource that needs cleanup, you stick it in an object of automatic storage duration so you don't need to worry about cleaning it up. This applies to any resource, be it memory, open files, network connections, or whatever you fancy.

This automatic_pointer thing already exists in various forms, I've just provided it to give an example. A very similar class exists in the standard library called std::unique_ptr .

There's also an old one (pre-C++11) named auto_ptr but it's now deprecated because it has a strange copying behaviour.

And then there are some even smarter examples, like std::shared_ptr , that allows multiple pointers to the same object and only cleans it up when the last pointer is destroyed.


A step by step explanation:

// 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());

So by the end of this, you have an object on the heap with no pointer to it, so it's impossible to delete.

The other sample:

A *object1 = new A();

is a memory leak only if you forget to delete the allocated memory:

delete object1;

In C++ there are objects with automatic storage, those created on the stack, which are automatically disposed of, and objects with dynamic storage, on the heap, which you allocate with new and are required to free yourself with delete . (this is all roughly put)

Think that you should have a delete for every object allocated with new .

EDIT

Come to think of it, object2 doesn't have to be a memory leak.

The following code is just to make a point, it's a bad idea, don't ever like code like this:

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;
    }
}

In this case, since other is passed by reference, it will be the exact object pointed to by new B() . Therefore, getting its address by &other and deleting the pointer would free the memory.

But I can't stress this enough, don't do this. It's just here to make a point.


Given two "objects":

obj a;
obj b;

They won't occupy the same location in memory. In other words, &a != &b

Assigning the value of one to the other won't change their location, but it will change their contents:

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

Intuitively, pointer "objects" work the same way:

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

Now, let's look at your example:

A *object1 = new A();

This is assigning the value of new A() to object1 . The value is a pointer, meaning object1 == new A() , but &object1 != &(new A()) . (Note that this example is not valid code, it is only for explanation)

Because the value of the pointer is preserved, we can free the memory it points to: delete object1; Due to our rule, this behaves the same as delete (new A()); which has no leak.


For you second example, you are copying the pointed-to object. The value is the contents of that object, not the actual pointer. As in every other case, &object2 != &*(new A()) .

B object2 = *(new B());

We have lost the pointer to the allocated memory, and thus we cannot free it. delete &object2; may seem like it would work, but because &object2 != &*(new A()) , it is not equivalent to delete (new A()) and so invalid.

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

上一篇: '新运营商'和'运营商新'之间的区别?

下一篇: 为什么使用'new'导致内存泄漏?