Memory deallocation inside a member function - c++

I was thinking about a this situation not for a real implementation but to understand better how pointers works.
class foo(){
foo();
~foo();
void doComplexThings(const std::vector<int*>& v){
int* copy;
for(int i = 0; i < v.size(); i++){
copy = v[i];
// do some stuffs
}
}
}
main(){
std::vector<int*> myVector; // suppose we have 100 elements
doComplexThings(myVector);
for(int i = 0; i < myVector.size(); i++){
delete myVector[i];
}
myVector.clear();
}
Ok, I know that have no sense to copy v[i] inside an other pointer, but I was thinking: copy do a memory leak?
After the execution of doComplexThings(), copy will continue to exist and will occupy space in the heap?
After deleting all elements it will continue to exist and point to a deallocated memory?
So logically if I do this things with complex objects I'll keep occupy the memory with unreference object? Or copy is saved in the stack because I don't use new? And at the end of doComplexThings it will be deleted?
I'm a bit confused, thanks!

There is some confusion on the topic of pointers in the C++ community. While it is true that smart pointers have been added to the library to alleviate problems with dynamic memory allocation, raw pointers are not obsolete. In fact, whenever you want to inspect another object without owning it, you should use a reference or raw pointer, depending on which suits your needs. If the concept of ownership is unclear to you, think of an object as being owned by another object if the latter is responsible for cleaning up afterwards (deleting the former).
For example most uses of new and delete should be replaces with the following (omitting std for brevity):
{
auto ptr_to_T = make_unique<T>(//constructor params);
do_stuff_with_smart_ptr(ptr_to_T);
do_stuff_with_T(*ptr_to_T);
do_stuff_with_raw_ptr(ptr_to_T.get());
} // automatic release of memory allocated with make_unique()
Notice how a function that takes a T* doesn't need a smart pointer if it doesn't keep a copy of the T* it is given, because it doesn't affect the lifetime of the object. The object is guaranteed to be alive past the return point of do_stuff_with_T() and its function signature signals that it doesn't own the object by taking a raw pointer.
On the other hand, if you need to pass the pointer to an object that is allowed to keep the pointer and reference it later, it is unclear when the object will need to be destroyed and most importantly by whom. This is solved via a shared pointer.
ClassThatNeedsSharedOwnership shared_owner;
{
auto ptr_to_T = make_shared<T>(//constructor params);
shared_owner.set_T(ptr_to_T);
// do a lot of stuff
}
// At this point ptr_to_T is destroyed, but shared_owner might keep the object alive
So how does the above factor in to your code. First of all, if the vector is supposed to own (keep alive) the ints it points to, it needs to hold unique_ptr<int> or shared_ptr<int>. If it is just pointing to ints held by something else, and they are guaranteed to be alive until after the vector is destroyed, you are fine with int*. In this case, it should be evident that a delete is never necessary, because by definition your vector and the function working on the vector are not responsible for cleaning-up!
Finally, you can make your code more readable by changing the loop to this (C++11 which you've tagged in the post):
for (auto copy : v){
// equivalent to your i-indexed loop with copy = v[i];
// as long as you don't need the value of i
do_stuff_to_int_ptr(copy);
// no delete, we don't own the pointee
}
Again this is only true if some other object holds the ints and releases them, or they are on the stack but guaranteed to be alive for the whole lifetime of vector<int*> that points to them.

No additional memory is allocated on the heap when you do this:
copy = v[i];
variable copy points to the same address as v[i], but no additional array is allocated, so there would be no memory leak.
A better way of dealing with the situation is to avoid raw pointers in favor of C++ smart pointers or containers:
std::vector<std::vector<int>> myVector;
Now you can remove the deletion loop, which is an incorrect way of doing it for arrays allocated with new int[length] - it should use delete[] instead:
delete[] myVector[i];

Basically you're illustrating the problem with C pointers which lead to the introduction of C++ unique and shared pointers. If you pass a vector of allocated pointers to an opaque member function, you've no way of knowing whether that function hangs onto them or not, so you don't know whether to delete the pointer. In fact in your example you don't seem to, "copy" goes out of scope.
The real answer is that you should only seldom use allocated pointers in C++ at all. The stl vector will serve as a safer, easier to use version of malloc / new. Then you should pass them about as const & to prevent functions from changing them. If you do need an allocated pointer, make one unique_ptr() and then you know that the unique_ptr() is the "owner" of the memory.

Related

Can I keep vector data even after out of scope

I come from a C background. I used to allocate memory/array, for example, sending it to somewhere else, and the pointer stayed there, even after, the scope where it was allocated was destroyed.
Now, if I do the same with vectors : initialize, pass it by reference, and then keep that reference saved somewhere. After the initial method, that actually created the vector, goes out of scope, would it be destroyed ? Or as the pointer to it is still saved, it will be kept.
std::vector frees the memory it holds when it is destroyed. Holding a reference to an object that gets destroyed is very bad. Accessing it is UB. General rule: Do not store references, only use them where you can be sure that the object exists for the entire scope, e.g. as parameter of a function.
If you want to keep a copy of the data, simply copy the std::vector. No reference needed.
If you want to be able to access the data from different locations, and have it live as long as at least one location still has a reference/pointer to it, don't use std::vector, use std::shared_ptr.
If you want to combine the benefits of std::vector with the benefits of shared memory that lives until the last place lets go of it, combine them: std::shared_ptr<std::vector<...>>.
If you want to have the std::vector live in one place for a bit, and then live in another place but not in the first place anymore, use move semantics:
std::vector<int> foo = {1, 2, 3};
std::vector<int> bar = std::move(foo); // bar now holds the data that foo held, foo is empty, no copy was performed
A pointer to an array on the stack will not keep the array alive, I suppose thats the same in C. Now a vector is not an array. It is a wrapper around a heap allocated array which frees the memory of the array when it goes out of scope.
... because a pointer to it is still saved it will still be kept?
No! A pointer or reference to a std::vector will not keep the vector alive. The canonical wrong example is:
std::vector<T>& foo() {
std::vector<T> x;
return x;
} // baaam !
The reference returned from the function is dangling. YOu cannot do anything with it. The correct way would be to return by value and rely on return value optimization:
std::vector<T> foo() {
std::vector<T> x;
return x;
}
If you do:
auto y = foo();
No copying is involved, thanks to NRVO.
PS: Compilers should warn you about returning a reference to a local variable.
No if I do the same with vectors, I initialize a vector, pass it by reference, then keep the reference saved somewhere. After the initial method that actually created the vector goes out of scope, would it be destoryed?
Yes.
or because a pointer to it is still saved it will still be kept?
No.
You can have dangling pointers in C++ just like you can in C. It's exactly the same.
This is also often the case for references (though in some cases the lifetime of the object is extended for a little bit).
It is true that the vector's data is internally managed by the vector, but that's by-the-by since you're asking about the vector itself. Forget the vector and ask the same question about an int, then you'll realise the answer is just as you'd expect it to be in C.
The existing answers are good, will add here:
block A
{
vector<int> my_vec(10, 0);
//...something...
}
block B
The my_vec vector will go out of scope and be destroyed at the closing bracket. Now that's stl (Standard Template Library) vectors.
You can also use C-style arrays (but with different syntax). For very large arrays, I have found the allocation time with a dynamically-allocated array to be faster than STL vectors.
//static, goes out of scope and memory handled at the end of code block
int arr0[10];
//dynamic, not destroyed unless delete called.
int* arr1 = new int[10];
//...work with arr1...
delete [] arr1;
Just like in C, you need to take care of de-allocating any memory you create using new.

Can you dynamically allocate a vector?

I need my vector container to persist past the end of the function that allocates it.
void initVector() {
vector<obj1*> R;
}
Why is this not valid?
void initVector() {
vector<obj1*> R = new vector<obj1*>;
}
It should be vector<obj1*>* R = new vector<obj1*>;. However, with C++11's move semantics, using pointers or references to avoid expensive copies is usually not needed. In the case of a vector, the below code doesn't copy tempVec - it will move it at least. More likely that compiler will elide the copy. You can read more about it here.
vector<obj1*> getVector()
{
vector<obj1*> tempVec;
//populate tempVec;
return tempVec;//The standard guarantees a move at least. Compilers are free to elide this copy.
}
EDIT : As #juanchopanza points out in the comments, if you have a good reason to be doing this, be wary of managing the lifetime of the vector allocated on the heap, R. This isn't an issue specific to this statement - it applies to dynamically allocated structures in general. However, it might need special mention here since you have a vector of pointers. In addition to correctly managing the lifetime of R, you also need to carefully manage the lifetimes of the obj1* it contains. Objects allocated on the heap don't get deleted when the pointer holding them goes out of scope. You will have to manually call delete on a pointer to that memory location when you are done using it. This applies both to the vector* R and, unless owned by some other part of your program, to the obj* that it contains.

When is a C++ destructor called?

Basic Question: when does a program call a class' destructor method in C++? I have been told that it is called whenever an object goes out of scope or is subjected to a delete
More specific questions:
1) If the object is created via a pointer and that pointer is later deleted or given a new address to point to, does the object that it was pointing to call its destructor (assuming nothing else is pointing to it)?
2) Following up on question 1, what defines when an object goes out of scope (not regarding to when an object leaves a given {block}). So, in other words, when is a destructor called on an object in a linked list?
3) Would you ever want to call a destructor manually?
1) If the object is created via a pointer and that pointer is later deleted or given a new address to point to, does the object that it was pointing to call its destructor (assuming nothing else is pointing to it)?
It depends on the type of pointers. For example, smart pointers often delete their objects when they are deleted. Ordinary pointers do not. The same is true when a pointer is made to point to a different object. Some smart pointers will destroy the old object, or will destroy it if it has no more references. Ordinary pointers have no such smarts. They just hold an address and allow you to perform operations on the objects they point to by specifically doing so.
2) Following up on question 1, what defines when an object goes out of scope (not regarding to when an object leaves a given {block}). So, in other words, when is a destructor called on an object in a linked list?
That's up to the implementation of the linked list. Typical collections destroy all their contained objects when they are destroyed.
So, a linked list of pointers would typically destroy the pointers but not the objects they point to. (Which may be correct. They may be references by other pointers.) A linked list specifically designed to contain pointers, however, might delete the objects on its own destruction.
A linked list of smart pointers could automatically delete the objects when the pointers are deleted, or do so if they had no more references. It's all up to you to pick the pieces that do what you want.
3) Would you ever want to call a destructor manually?
Sure. One example would be if you want to replace an object with another object of the same type but don't want to free memory just to allocate it again. You can destroy the old object in place and construct a new one in place. (However, generally this is a bad idea.)
// pointer is destroyed because it goes out of scope,
// but not the object it pointed to. memory leak
if (1) {
Foo *myfoo = new Foo("foo");
}
// pointer is destroyed because it goes out of scope,
// object it points to is deleted. no memory leak
if(1) {
Foo *myfoo = new Foo("foo");
delete myfoo;
}
// no memory leak, object goes out of scope
if(1) {
Foo myfoo("foo");
}
Others have already addressed the other issues, so I'll just look at one point: do you ever want to manually delete an object.
The answer is yes. #DavidSchwartz gave one example, but it's a fairly unusual one. I'll give an example that's under the hood of what a lot of C++ programmers use all the time: std::vector (and std::deque, though it's not used quite as much).
As most people know, std::vector will allocate a larger block of memory when/if you add more items than its current allocation can hold. When it does this, however, it has a block of memory that's capable of holding more objects than are currently in the vector.
To manage that, what vector does under the covers is allocate raw memory via the Allocator object (which, unless you specify otherwise, means it uses ::operator new). Then, when you use (for example) push_back to add an item to the vector, internally the vector uses a placement new to create an item in the (previously) unused part of its memory space.
Now, what happens when/if you erase an item from the vector? It can't just use delete -- that would release its entire block of memory; it needs to destroy one object in that memory without destroying any others, or releasing any of the block of memory it controls (for example, if you erase 5 items from a vector, then immediately push_back 5 more items, it's guaranteed that the vector will not reallocate memory when you do so.
To do that, the vector directly destroys the objects in the memory by explicitly calling the destructor, not by using delete.
If, perchance, somebody else were to write a container using contiguous storage roughly like a vector does (or some variant of that, like std::deque really does), you'd almost certainly want to use the same technique.
Just for example, let's consider how you might write code for a circular ring-buffer.
#ifndef CBUFFER_H_INC
#define CBUFFER_H_INC
template <class T>
class circular_buffer {
T *data;
unsigned read_pos;
unsigned write_pos;
unsigned in_use;
const unsigned capacity;
public:
circular_buffer(unsigned size) :
data((T *)operator new(size * sizeof(T))),
read_pos(0),
write_pos(0),
in_use(0),
capacity(size)
{}
void push(T const &t) {
// ensure there's room in buffer:
if (in_use == capacity)
pop();
// construct copy of object in-place into buffer
new(&data[write_pos++]) T(t);
// keep pointer in bounds.
write_pos %= capacity;
++in_use;
}
// return oldest object in queue:
T front() {
return data[read_pos];
}
// remove oldest object from queue:
void pop() {
// destroy the object:
data[read_pos++].~T();
// keep pointer in bounds.
read_pos %= capacity;
--in_use;
}
~circular_buffer() {
// first destroy any content
while (in_use != 0)
pop();
// then release the buffer.
operator delete(data);
}
};
#endif
Unlike the standard containers, this uses operator new and operator delete directly. For real use, you probably do want to use an allocator class, but for the moment it would do more to distract than contribute (IMO, anyway).
When you create an object with new, you are responsible for calling delete. When you create an object with make_shared, the resulting shared_ptr is responsible for keeping count and calling delete when the use count goes to zero.
Going out of scope does mean leaving a block. This is when the destructor is called, assuming that the object was not allocated with new (i.e. it is a stack object).
About the only time when you need to call a destructor explicitly is when you allocate the object with a placement new.
1) Objects are not created 'via pointers'. There is a pointer that is assigned to any object you 'new'. Assuming this is what you mean, if you call 'delete' on the pointer, it will actually delete (and call the destructor on) the object the pointer dereferences. If you assign the pointer to another object there will be a memory leak; nothing in C++ will collect your garbage for you.
2) These are two separate questions. A variable goes out of scope when the stack frame it's declared in is popped off the stack. Usually this is when you leave a block. Objects in a heap never go out of scope, though their pointers on the stack may. Nothing in particular guarantees that a destructor of an object in a linked list will be called.
3) Not really. There may be Deep Magic that would suggest otherwise, but typically you want to match up your 'new' keywords with your 'delete' keywords, and put everything in your destructor necessary to make sure it properly cleans itself up. If you don't do this, be sure to comment the destructor with specific instructions to anyone using the class on how they should clean up that object's resources manually.
Pointers -- Regular pointers don't support RAII. Without an explicit delete, there will be garbage. Fortunately C++ has auto pointers that handle this for you!
Scope -- Think of when a variable becomes invisible to your program. Usually this is at the end of {block}, as you point out.
Manual destruction -- Never attempt this. Just let scope and RAII do the magic for you.
To give a detailed answer to question 3: yes, there are (rare) occasions when you might call the destructor explicitly, in particular as the counterpart to a placement new, as dasblinkenlight observes.
To give a concrete example of this:
#include <iostream>
#include <new>
struct Foo
{
Foo(int i_) : i(i_) {}
int i;
};
int main()
{
// Allocate a chunk of memory large enough to hold 5 Foo objects.
int n = 5;
char *chunk = static_cast<char*>(::operator new(sizeof(Foo) * n));
// Use placement new to construct Foo instances at the right places in the chunk.
for(int i=0; i<n; ++i)
{
new (chunk + i*sizeof(Foo)) Foo(i);
}
// Output the contents of each Foo instance and use an explicit destructor call to destroy it.
for(int i=0; i<n; ++i)
{
Foo *foo = reinterpret_cast<Foo*>(chunk + i*sizeof(Foo));
std::cout << foo->i << '\n';
foo->~Foo();
}
// Deallocate the original chunk of memory.
::operator delete(chunk);
return 0;
}
The purpose of this kind of thing is to decouple memory allocation from object construction.
Remember that Constructor of an object is called immediately after the memory is allocated for that object and whereas the destructor is called just before deallocating the memory of that object.
Whenever you use "new", that is, attach an address to a pointer, or to say, you claim space on the heap, you need to "delete" it.
1.yes, when you delete something, the destructor is called.
2.When the destructor of the linked list is called, it's objects' destructor is called. But if they are pointers, you need to delete them manually.
3.when the space is claimed by "new".
Yes, a destructor (a.k.a. dtor) is called when an object goes out of scope if it is on the stack or when you call delete on a pointer to an object.
If the pointer is deleted via delete then the dtor will be called. If you reassign the pointer without calling delete first, you will get a memory leak because the object still exists in memory somewhere. In the latter instance, the dtor is not called.
A good linked list implementation will call the dtor of all objects in the list when the list is being destroyed (because you either called some method to destory it or it went out of scope itself). This is implementation dependent.
I doubt it, but I wouldn't be surprised if there is some odd circumstance out there.
If the object is created not via a pointer(for example,A a1 = A();),the destructor is called when the object is destructed, always when the function where the object lies is finished.for example:
void func()
{
...
A a1 = A();
...
}//finish
the destructor is called when code is execused to line "finish".
If the object is created via a pointer(for example,A * a2 = new A();),the destructor is called when the pointer is deleted(delete a2;).If the point is not deleted by user explictly or given a new address before deleting it, the memory leak is occured. That is a bug.
In a linked list, if we use std::list<>, we needn't care about the desctructor or memory leak because std::list<> has finished all of these for us. In a linked list written by ourselves, we should write the desctructor and delete the pointer explictly.Otherwise, it will cause memory leak.
We rarely call a destructor manually. It is a function providing for the system.
Sorry for my poor English!

Storing a pointer to an object created in a method

Using C++:
I currently have a method in which if an event occurs an object is created, and a pointer to that object is stored in a vector of pointers to objects of that class. However, since objects are destroyed once the local scope ends, does this mean that the pointer I stored to the object in the vector is now null or undefined? If so, are there any general ways to get around this - I'm assuming the best way would be to allocate on the heap.
I ask this because when I try to access the vector and do operations on the contents I am getting odd behavior, and I'm not sure if this could be the cause or if it's something totally unrelated.
It depends on how you allocate the object. If you allocate the object as an auto variable, (i.e. on the stack), then any pointer to that object will become invalid once the object goes out of scope, and so dereferencing the pointer will lead to undefined behavior.
For example:
Object* pointer;
{
Object myobject;
pointer = &myobject;
}
pointer->doSomething(); // <--- INVALID! myobject is now out of scope
If, however, you allocate the object on the Heap, using the new operator, then the object will remain valid even after you exit the local scope. However, remember that there is no automatic garbage collection in C++, and so you must remember to delete the object or you will have a memory leak.
So if I understand correctly you have described the following scenario:
class MyClass
{
public:
int a;
SomeOtherClass b;
};
void Test()
{
std::vector<MyClass*> v;
for (int i=0; i < 10; ++i)
{
MyClass b;
v.push_back(&b);
}
// now v holds 10 items pointers to strange and scary places.
}
This is definitely bad.
There are two primary alternatives:
allocate the objects on the heap using new.
make the vector hold instances of MyClass (i.e. std::vector<MyClass>)
I generally prefer the second option when possible. This is because I don't have to worry about manually deallocating memory, the vector does it for me. It is also often more efficient. The only problem, is that I would have to be sure to create a copy constructor for MyClass. That means a constructor of the form MyClass(const MyClass& other) { ... }.
If you store a pointer to an object, and that object is destroyed (e.g. goes out of scope), that pointer will not be null, but if you try to use it you will get undefined behavior. So if one of the pointers in your vector points to a stack-allocated object, and that object goes out of scope, that pointer will become impossible to use safely. In particular, there's no way to tell whether a pointer points to a valid object or not; you just have to write your program in such a way that pointers never ever ever point to destroyed objects.
To get around this, you can use new to allocate space for your object on the heap. Then it won't be destroyed until you delete it. However, this takes a little care to get right as you have to make sure that your object isn't destroyed too early (leaving another 'dangling pointer' problem like the one you have now) or too late (creating a memory leak).
To get around that, the common approach in C++ is to use what's called (with varying degrees of accuracy) a smart pointer. If you're new to C++ you probably shouldn't worry about these yet, but if you're feeling ambitious (or frustrated with memory corruption bugs), check out shared_ptr from the Boost library.
If you have a local variable, such as an int counter, then it will be out of scope when you exit the function, but, unless you have a C++ with a garbage collector, then your pointer will be in scope, as you have some global vector that points to your object, as long as you did a new for the pointer.
I haven't seen a situation where I have done new and my memory was freed without me doing anything.
To check (in no particular order):
Did you hit an exception during construction of member objects whose pointers you store?
Do you have a null-pointer in the container that you dereference?
Are you using the vector object after it goes out of scope? (Looks unlikely, but I still have to ask.)
Are you cleaning up properly?
Here's a sample to help you along:
void SomeClass::Erase(std::vector<YourType*> &a)
{
for( size_t i = 0; i < a.size(); i++ ) delete a[i];
a.clear();
}

How do stl containers get deleted?

How does container object like vector in stl get destroyed even though they are created in heap?
EDIT
If the container holds pointers then how to destroy those pointer objects
An STL container of pointer will NOT clean up the data pointed at. It will only clean up the space holding the pointer. If you want the vector to clean up pointer data you need to use some kind of smart pointer implementation:
{
std::vector<SomeClass*> v1;
v1.push_back(new SomeClass());
std::vector<boost::shared_ptr<SomeClass> > v2;
boost::shared_ptr<SomeClass> obj(new SomeClass);
v2.push_back(obj);
}
When that scope ends both vectors will free their internal arrays. v1 will leak the SomeClass that was created since only the pointer to it is in the array. v2 will not leak any data.
If you have a vector<T*>, your code needs to delete those pointers before delete'ing the vector: otherwise, that memory is leaked.
Know that C++ doesn't do garbage collection, here is an example of why (appologies for syntax errors, it has been a while since I've written C++):
typedef vector<T*> vt;
⋮
vt *vt1 = new vt, *vt2 = new vt;
T* t = new T;
vt1.push_back(t);
vt2.push_back(t);
⋮
delete vt1;
The last line (delete vt1;) clearly should not delete the pointer it contains; after all, it's also in vt2. So it doesn't. And neither will the delete of vt2.
(If you want a vector type that deletes pointers on destroy, such a type can of course be written. Probably has been. But beware of delete'ing pointers that someone else is still holding a copy of.)
When a vector goes out of scope, the compiler issues a call to its destructor which in turn frees the allocated memory on the heap.
This is somewhat of a misnomer. A vector, as with most STL containers, consists of 2 logical parts.
the vector instance
the actual underlying array implementation
While configurable, #2 almost always lives on the heap. #1 however can live on either the stack or heap, it just depends on how it's allocated. For instance
void foo() {
vector<int> v;
v.push_back(42);
}
In this case part #1 lives on the stack.
Now how does #2 get destroyed? When a the first part of a vector is destroyed it will destroy the second part as well. This is done by deleting the underlying array inside the destructor of the vector class.
If you store pointers in STL container classes you need to manually delete them before the object gets destroyed. This can be done by looping through the whole container and deleting each item, or by using some kind of smart pointer class. However do not use auto_ptr as that just does not work with containers at all.
A good side effect of this is that you can keep multiple containers of pointers in your program but only have those objects owned by one of those containers, and you only need to clean up that one container.
The easiest way to delete the pointers would be to do:
for (ContainerType::iterator it(container.begin()); it != container.end(); ++it)
{
delete (*it);
}
Use either smart pointers inside of the vector, or use boost's ptr_vector. It will automatically free up the allocated objects inside of it. There are also maps, sets, etc.
http://www.boost.org/doc/libs/1_37_0/libs/ptr_container/doc/ptr_vector.html
and the main site:
http://www.boost.org/doc/libs/1_37_0/libs/ptr_container/doc/ptr_container.html
As with any other object in the heap, it must be destroyed manually (with delete).
To answer your first question:
There's nothing special about STL classes (I hope). They function exactly like other template classes. Thus, they are not automatically destroyed if allocated on the heap, because C++ has no garbage collection on them (unless you tell it to with some fancy autoptr business or something). If you allocate it on the stack (without new) it will most likely be managed by C++ automatically.
For your second question, here's a very simple ArrayOfTen class to demonstrate the basics of typical memory management in C++:
/* Holds ten Objects. */
class ArrayOfTen {
public:
ArrayOfTen() {
m_data = new Object[10];
}
~ArrayOfTen() {
delete[] m_data;
}
Object &operator[](int index) {
/* TODO Range checking */
return m_data[index];
}
private:
Object *m_data;
ArrayOfTen &operator=(const ArrayOfTen &) { }
};
ArrayOfTen myArray;
myArray[0] = Object("hello world"); // bleh
Basically, the ArrayOfTen class keeps an internal array of ten Object elements on the heap. When new[] is called in the constructor, space for ten Objects is allocated on the heap, and ten Objects are constructed. Simiarly, when delete[] is called in the destructor, the ten Objects are deconstructed and then the memory previously allocated is freed.
For most (all?) STL types, resizing is done behind the scenes to make sure there's enough memory set asside to fit your elements. The above class only supports arrays of ten Objects. It's basically a very limiting typedef of Object[10].
To delete the elements pointed at, I wrote a simple functor:
template<typename T>
struct Delete {
void operator()( T* p ) const { delete p; }
};
std::vector< MyType > v;
// ....
std::for_each( v.begin(), v.end(), Delete<MyType>() );
But you should fallback on shared pointers when the vector's contents are to be ... ehm... shared. Yes.
A functor that deletes pointers from STL sequence containers
The standard STL containers place a copy of the original object into the container, using the copy constructor. When the container is destroyed the destructor of each object in the container is also called to safely destroy the object.
Pointers are handled the same way.
The thing is pointers are POD data. The copy constructor for a pointer is just to copy the address and POD data has no destructor. If you want the container to manage a pointer you need to:
Use a container of smart pointers. (eg shared pointer).
Use a boost ptr container.
I prefer the pointer container:
The pointer containers are the same as the STL containers except you put pointers into them, but the container then takes ownership of the object the pointer points at and will thus deallocate the object (usually by calling delete) when the container is destroyed.
When you access members of a ptr container they are returned via reference so they behave just like a standard container for use in the standard algorithms.
int main()
{
boost::ptr_vector<int> data;
data.push_back(new int(5));
data.push_back(new int(6));
std::cout << data[0] << "\n"; // Prints 5.
std::cout << data[1] << "\n"; // Prints 6.
} // data deallocated.
// This will also de-allocate all pointers that it contains.
// by calling delete on the pointers. Therefore this will not leak.
One should also point out that smart pointers in a container is a valid alternative, unfortunately std::auto_ptr<> is not a valid choice of smart pointer for this situation.
This is because the STL containers assume that the objects they contain are copyable, unfortunately std::auto_ptr<> is not copyable in the traditional sense as it destroys the original value on copy and thus the source of the copy can not be const.
STL containers are like any other objects, if you instantiate one it is created on the stack:
std::vector<int> vec(10);
Just like any other stack variable, it only lives in the scope of the function it is defined in, and doesn't need to be manually deleted. The destructor of STL containers will call the destructor of all elements in the container.
Keeping pointers in a container is a dicey issue. Since pointers don't have destructors, I would say you would never want to put raw pointers into an STL container. Doing this in an exception safe way will be very difficult, you'd have to litter your code with try{}finally{} blocks to ensure that the contained pointers are always deallocated.
So what should you put into containers instead of raw pointers? +1 jmucchiello for bringing up boost::shared_ptr. boost::shared_ptr is safe to use in STL containers (unlike std::auto_ptr). It uses a simple reference counting mechanism, and is safe to use for data structures that don't contain cycles.
What would you need for data structures that contain cycles? In that case you probably want to graduate to garbage collection, which essentially means using a different language like Java. But that's another discussion. ;)