eran otzap
eran otzap

Reputation: 12533

C++ memory management clarification

I'm new to c++.

I've got a Rectangle class. When I create a Rectangle object like this:

Rectangle R1(10,10,90,20);

(In general what would be the correct way to create an object in c++?)

To my understanding, if I create it without new the object sits on the stack and does not need to be deleted at the end of its life time. And if do create it with new

Rectangle* R = new Rectangle(1,1,1,1);

it will be placed on the heap and would need to be de-allocated using delete.

Upvotes: 0

Views: 109

Answers (3)

Mooing Duck
Mooing Duck

Reputation: 66922

Rectangle R1(10,10,90,20);

This creates a variable with "automatic" duration. It is automatically destroyed when the code flow exits the scope. If it's not in a function, that means when the execution of your code completes. Usually (but not always) it sits on some sort of stack.

Rectangle* R = new Rectangle(1,1,1,1);
Rectangle* P(new Rectangle(1,1,1,1)); //rarely used

This part is confusing: The variable R is a pointer with automatic duration (like above). It points at an Rectangle with "dynamic" duration. Usually (but not always) the dynamic object sits on some sort of heap. The rectangle is destroyed only when you explicitly destroy it with delete R;. This means if the function ends and there is no other copy of R, it becomes impossible to delete, and will remain in memory until your program ends. This is called a memory leak.

In C++, dynamic memory is best handled with a smart pointer, such as std::unique_ptr, so that you can't accidentally forget to delete it, even if the code is crashing.

std::unique_ptr<Rectangle> R(new Rectangle(1,1,1,1));

Upvotes: 4

Kerrek SB
Kerrek SB

Reputation: 477040

Lots of the things you say are either implementation details or dependent on the context. Consider this:

// file.cpp

Rectangle r1(1,2,3,4);

int main()
{
  Rectangle r2 = r1;
  Rectangle * r3 = new Rectangle(r1);
}

Here r1 has static storage and static (= permanent) lifetime, while r2 has automatic storage and automatic (= scoped) lifetime. That is, r1 constructed at program start and destroyed at the end (after main returns), while r2 is constructed at declaration and destroyed at the end of its scope (i.e. the function body scope in this case).

The pointer r3 points to a Rectangle object of dynamic storage and dynamic (= manual) lifetime. The object *r3 comes to life at the new expression, and it will only be destroyed at the user's request via a matching delete expression (or perhaps a manual destructor call). Since we don't destroy it, this is in fact a leak.

Nothing is known about the memory used by *r3, other than that this memory is allocated by the static member function Rectangle::operator new() if it exists, or otherwise by the global allocation function ::operator new. The global version's memory is typically referred to as the "free store".

(All three objects r1, r2 and *r3 are supposedly equal, since r2 and *r3 are constructed as copies of r1.)

The situation gets even more interesting when you consider member variables: struct Foo { Rectangle r; };.

Upvotes: 1

Ed Swangren
Ed Swangren

Reputation: 124642

  1. R1 is created with automatic storage duration. This means that, in practice, it will be allocated on a stack-like structure. It doesn't have to be mind you, a 'stack' is just convenient and common. You have to call new (or malloc if you really want to for some silly reason... don't) to allocate memory dynamically.

  2. See above.

  3. Yes, anything you new you must delete. Typically a class will manage this for you. Take for example an std::vector<T>. You allocate the vector on the stack, but the internal data (i.e., an array of T) is allocated dynamically. When the vector goes out of scope it delete []s the dynamically allocated array for you in it's destructor, allowing you to remain pleasantly ignorant of the underlying memory management details.

Upvotes: 0

Related Questions