views:

235

answers:

7

I have a struct that contains pointers:

struct foo
{
    char* f;
    int* d;
    wchar* m;
}

I have a vector of shared pointers to these structs:

vector<shared_ptr<foo>> vec;

vec is allocated on the stack. When it passes out of scope at the end of the method, its destructor will be called. (Right?) That will in turn call the destructor of each element in the vector. (Right?) Does calling delete foo delete just the pointers such as foo.f, or does it actually free the memory from the heap?

+1  A: 

It only deletes the pointers.

Noah Roberts
+1  A: 

You don't call delete f where f is an object of type foo if f is stack allocated. You also don't call delete f on a heap allocated object of type foo if that address is stored in a shared pointer. shared_ptr objets will call delete for you when the last reference is freed.

Since your vector stores smart pointers they will also fall out of scope when your vector falls out of scope and the foo destructor will be called and associated memory freed. The memory of foo is only the size of 3 pointers though. Not what those pointers contain.

If the members of foo are heap allocated, then you will need to delete those separately. For example maybe within the foo destructor if the memory they point to is not shared between objects.


When it passes out of scope at the end of the method, its destructor will be called. (Right?)

Right.

That will in turn call the destructor of each element in the vector. (Right?)

Right. The destructor of the smart pointer.

or does it actually free the memory from the heap?

It calls the destructor of the smart pointer, if there are no more references to that pointer then the object it contains will be deleted and its memory will be freed.

Brian R. Bondy
+7  A: 
delete foo;

will delete the memory allocated to the foo structure, which includes the three pointers. But the memory pointed to by the pointers themselves will only be deleted if you implement a destructor that explicitly deletes them.

bshields
Or alternately, change f, d, and m to use auto or shared pointers.
Brendan Long
A: 

What if you allocate memory dynamically inside that struct ? What will happen if the vector destructor is called? How can you free all the memory allocated?

Ilea Cristian
+1  A: 

There appears to be some terminological mixup in your question. Destructor of the vector will call destructors for shared_ptr elements, which in turn will internally perform delete on their stored pointers (if necessary).

Calling delete foo, where foo is a pointer to struct foo, will call the destructor of struct foo and then deallocate memory occupied by *foo.

Destructor of the above struct foo does absolutely nothing. It is trivial. If will not make any attempts to deallocate memory pointed by struct foo::f or any other members. Why would it? It does not and cannot know whether that memory should be deallocated.

In fact, because struct foo::~foo is trivial, the compilers will not normally even attempt to call it.

AndreyT
+2  A: 

If you have dynamically allocated foo, e.g.:

foo* f = new foo;

then delete f will destroy the dynamically allocated foo object including the pointers it contains but not anything pointed to by the pointers, if they do indeed point at dynamically allocated objects or arrays of objects.

If you've assigned a dynamically allocated foo object (i.e. the result of new foo) to a shared_ptr (assuming tr1 or boost) then when the last shared_ptr referring to that object goes out of scope delete will be called on the pointer originally returned by new foo automatically. You don't have to do this manually.

If your object (foo) contains pointers to dynamically allocated objects that it owns (so need deallocating at the end of the lifetime of the foo), then it's highly recommended that you write a destructor to deallocate these objects in the correct way (which will depend on how they are allocated).

Once you've written a destructor you need to consider whether you need to write a copy constructor and copy-assingment operator. As you are using a vector of shared pointers you may decide that your objects should not be copied. If so you can declare these as private and need not provide an implementation.

You should also consider one or more constructors to ensure that your pointer members are initialized. If the pointer members are never initialized then if they are not assigned to during the lifetime of a foo then they will neither be null, nor point to a valid object and this is likely to cause an error in your destructor.

Charles Bailey
A: 

When it [vec] passes out of scope at the end of the method, its destructor will be called. (Right?)
Correct

That will in turn call the destructor of each element in the vector. (Right?)
Correct, this will delete the shared_ptr elements in the container, and if they are the last ones also the items they are sharing.

Does calling delete foo ...?
You cannot delete foo, it's a struct. You can delete an instance of foo.
Calling delete calls the destructor and frees the memory for the foo struct.

Does the foo destructor delete just the pointers such as foo::f, or does it actually free the memory from the heap?
That depends on the destructo, in this case you have a default destructor and so...
No, In the following example code you can see the some of the reasons why the default destructor associated with foo cannot cleanup any pointer referred items automatically.

{
 char ca='a', *cb=new char;
 int *i = (int*)malloc(sizeof(int));
 foo a;
 shared_ptr<foo> b = new foo();
 a.f = &ca;
 a.d = i;
 b.f = cb;
}
Greg Domjan