tags:

views:

230

answers:

9

Hi,

I have a few questions regarding memory handling in C++.

  1. What's the different with Mystruct *s = new Mystruct and Mystruct s? What happens in the memory?

  2. Looking at this code:

    struct MyStruct{
        int i;
        float f;
    };
    
    
    MyStruct *create(){
        MyStruct tmp;
        tmp.i = 1337;
        tmp.j = .5f;
        return &tmp;
    }
    
    
    int main(){
        MyStruct *s = create();
        cout << s->i;
    
    
    
    return 0;
    
    }

When is MyStruct tmp free'd? Why doesn't MyStruct tmp get automatically free'd in the end of create()?

Thank you!

+3  A: 

For question 1, you are looking at the heap memory and the stack memory. In short,

Mystruct S;

creates S on the stack. When S goes out of scope, it will be destroyed. Hence if S is inside a function, when the function returns, S is destroyed.

Whereas

MyStruct *S = new MyStruct();

Is on the heap. It is a block of memory set aside for programs to store variables in, and S will store a pointer to the start memory block of the new MyStruct. It will always be within the heap until you free it; if you do not free it when your program ends, you get the nefarious memory leak.

On to question 2 - the local MyStruct is destroyed upon the function exiting; the MyStruct pointer which points to its return value is pointing to undefined region. It may still work, because the OS has not yet reclaimed the memory, but it is definitely not correct behavior - or a safe thing to do.

Extrakun
You're right about everything.To add to what you said, it may still work on some compilers, or with a custom memory allocator, etc. However the C++ standard doesn't guarantee anything about it. Some debug allocators will write over freed memory with garbage data (or 0), which will cause your app to crash when it tries to access the object.
Merlyn Morgan-Graham
+8  A: 

When you use the new keyword to get a pointer, your struct is allocated on the heap which ensures it will persist for the lifetime of your application (or until it's deleted).

When you don't, the struct is allocated on the stack and will be destroyed when the scope it was allocated in terminates.

My understanding of your example (please don't hesitate to inform me if I'm wrong, anyone):

tmp will indeed be "freed" (not the best word choice for a stack variable) at the end of the function since it was allocated on the stack and that stack frame has been lost. The pointer/memory address you return does not have any meaning anymore, and if the code works, you basically just got lucky (nothing has overwritten the old data yet).

Sapph
Thanks everyone for your helpfull answers. When do you use dynamically memory handling and not? Whats the best thing to do in large projects with many objects and such thats need to be accessed outside scopes? Use 'new' and smart pointers or use copy constructor without 'new'?
shuwo
Now that would be a new question. But to answer it here: If you have lots of Objects that need to be accessed outside scopes you probably have some architecture headaches. I remember that being one of my major pain points with C++, too. Thankfully, with C# I don't need to care about this particular problem anymore.
TToni
A: 

Mystruct *s = new Mystruct;

Dynamically allocates s on the heap. It will not be automatically freed. (Also, s is a pointer, not directly a Mystruct).

Mystruct s;

Statically allocates s on the stack. It will be "freed" when it goes out of scope.*

Your code is invalid. When you refer to tmp outside of create, you are using a wild pointer to access dead memory. This results in undefined behavior.

  • Pretty much. Using it out of scope is undefined behavior, even if the value is still in memory.
Thom Smith
A: 

Q1:

Mystruct *s = new Mystryct;

Creates the structure variable on the heap, which is being pointed by variable s.

Mystruct s;

Here the structure is created on the stack.

Q2:

MyStruct *create(){ MyStruct tmp; tmp.i = 1337; return &tmp; }

is wrong!! You are creating a local struct variable on stack which vanishes when the function return and any reference to it will be invalid. You should dynamically allocate the variable and will have to manually deallocate it later say in main.

codaddict
+1  A: 

First:

Mystruct* s = new Mystruct;

The new Mystryct part allocates memory on the heap for an object of that type. In C++ it will also execute the default constructor of the type. The Mystruct* s part declares a pointer variable that points to the address of the first byte of the newly allocated object memory.

Second:

Mystruct s;

It'll do the same as the first with two differences, which can be simplified as: The allocated memory for the object is on the stack and there's no pointer variable pointing to the memory, instead s is that object. The address of to that object is &s, so a pointer that points at the object s shall be assigned the value &s.

Why doesn't MyStruct tmp get automatically free'd in the end of create()?

It does. The tmp destructor runs after the return statement, so the address returned by the function will be to a memory that will soon be overwritten by something else, which at best will cause a segmentation fault (or the equivalent) and at worst corrupt your data.

Johann Gerell
It was interesting that one of the answers did mention that you can define custom allocators... upvoted anyway.
David Rodríguez - dribeas
A: 

Mystruct *s = new Mystryct allocates on heap.
One needs to explicitly delete it.
Whereas Mystruct s allocates the structure on stack.
It automatically gets freed as the stack unwinds (Variable goes out of scope) so for Case 2, the tmp will be freed as soon as create() exits. So what you'll have returned is a dangling pointer which is very dangerous.

If it's too difficult, follow this rule of thumb,
For every new operator called, delete must be called in the end.
For every new[] operator called, delete[] must be called in the end.

use smart pointers which automatically delete the memory allocated instead of normal pointers. If you're returning objects from a function like in create, make sure you're allocating it using the new operator and not on stack like you've done in the example. Make sure that the caller calls delete on the pointer once he finishes with it.

Samrat Patil
A: 
  1. In Mystruct *s = new Mystruct there is static variable, pointer, that is allocated in the start of the function call on the stack. When this line is running, it's allocating on the heap the struct. In Mystruct s it allocates the struct on the stack, "staticly" when the function runs (the constructor, if any, will run in the decleration line).

  2. "Why doesn't MyStruct tmp get automatically free'd in the end of create()?" - well, it is. But, the memory still exist, so you can access it and it may contain the old values.

Y. Shoham
A: 
struct MyStruct{ int i; };

MyStruct create(){ MyStruct tmp; tmp.i = 1337; return tmp; }

int main(){

  MyStruct s = create();
  cout << s.i;

  return 0;
}

or

struct MyStruct{ int i; };

MyStruct* create(){ MyStruct* tmp = new MyStruct; tmp->i = 1337; return tmp; }

int main(){

  MyStruct* s = create();
  cout << s->i;
  delete s;    

  return 0;
}

would work. Because the copy constructor would create a copy of the struct when it is assigned to s in the first case. The whole new/delete stuff (dynamic memory allocation) belongs to the basics of C++. You do not have to use any new or delete to implement basic algorithms. Copy constructor and so on will always do the job and make the code easier to understand.

If you want to use new you should also read about autopointer and so on. There is no garbage collection of memory in C++. I think Thinking C++ explains the concepts of dynamic memory very well(chapter 13).

Totonga
You mean `return tmp;` in your function.
Alok
+1  A: 

Both of your questions deal with storage duration and scope.

First, when you dynamically allocate an object, the object and a pointer to it is valid until you free it. If it is an automatic variable (i.e., not dynamically allocated by new, malloc, etc., and not declared static), the variable goes out of scope as soon as the object's scope ends (usually that's the } at the same "level" as the one in which the object was defined). It also has "automatic storage duration", which means that the storage for it also goes away when the object is not in scope.

For your second question, tmp has a scope that ends with the ending } of create. It also has the same storage duration. A pointer to tmp is only valid within that storage duration. Once create() exits, the pointer to tmp becomes invalid, and cannot be used.

Alok
Good to see the `automatic` in the explanation. It's far too seldom used when explaining these things - probably overseen since it's not visible in the variable declaration.
Johann Gerell
@Johann: thanks.
Alok