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
In C# and Java, you use new to create an instance of any class and then you do not need to worry about destroying it later.
C++ also has a keyword "new" which creates an object but unlike in Java or C#, it is not the only way to create an object.
C++ has two mechanisms to create an object:
With automatic creation you create the object in a scoped environment: - in a function or - as a member of a class (or struct).
In a function you would create it this way:
int func()
{
A a;
B b( 1, 2 );
}
Within a class you would normally create it this way:
class A
{
B b;
public:
A();
};
A::A() :
b( 1, 2 )
{
}
In the first case, the objects are destroyed automatically when the scope block is exited. This could be a function or a scope-block within a function.
In the latter case the object b is destroyed together with the instance of A in which it is a member.
Objects are allocated with new when you need to control the lifetime of the object and then it requires delete to destroy it. With the technique known as RAII, you take care of the deletion of the object at the point you create it by putting it within an automatic object, and wait for that automatic object's destructor to take effect.
One such object is a shared_ptr which will invoke a "deleter" logic but only when all the instances of the shared_ptr that are sharing the object are destroyed.
In general, whilst your code may have many calls to new, you should have limited calls to delete and should always make sure these are called from destructors or "deleter" objects that are put into smart-pointers.
Your destructors should also never throw exceptions.
If you do this, you will have few memory leaks.
Well, you create a memory leak if you don't at some point free the memory you've allocated using the new
operator by passing a pointer to that memory to the delete
operator.
In your two cases above:
A *object1 = new A();
Here you aren't using delete
to free the memory, so if and when your object1
pointer goes out of scope, you'll have a memory leak, because you'll have lost the pointer and so can't use the delete
operator on it.
And here
B object2 = *(new B());
you are discarding the pointer returned by new B()
, and so can never pass that pointer to delete
for the memory to be freed. Hence another memory leak.
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.
When creating object2
you're creating a copy of the object you created with new, but you're also losing the (never assigned) pointer (so there's no way to delete it later on). To avoid this, you'd have to make object2
a reference.
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.
It's this line that is immediately leaking:
B object2 = *(new B());
Here you are creating a new B
object on the heap, then creating a copy on the stack. The one that has been allocated on the heap can no longer be accessed and hence the leak.
This line is not immediately leaky:
A *object1 = new A();
There would be a leak if you never delete
d object1
though.