basic question about std::vector

K

kathy

I am using std::vector in my program:

func()
{
std::vector <CMyClass *> vpMyClass;
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());

//???? Required ??????????????//
delete vpMyClass[0];
delete vpMyClass[1];
delete vpMyClass[2];

}

or vector automatically delete all pointer when it is out of the scope?
 
R

Rennie deGraaf

kathy said:
I am using std::vector in my program:

func()
{
std::vector <CMyClass *> vpMyClass;
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());

//???? Required ??????????????//
delete vpMyClass[0];
delete vpMyClass[1];
delete vpMyClass[2];

}

or vector automatically delete all pointer when it is out of the scope?

Vector just knows about the value that it's storing - a binary value of
the size of memory addresses on your system. It doesn't know or care
about what that value actually means. So, yes, if you store pointers to
dynamically allocated memory in a vector, you are responsible for
freeing the memory yourself.

Another perspective: If vectors containing pointers somehow knew to free
dynamically allocated objects before deleting the entries, then the
following code would probably crash your system:

func()
{
std::vector<char*> vec;
vec.push_back("a string");
vec.push_back(new char[100]);
vec.push_back(NULL);
}

The second thing that I push is a pointer to dynamically-allocated
memory that must be freed. The first, however, is a pointer to
statically-allocated memory, and attempting to delete it would result in
undefined behaviour. The third points to nothing at all, although I
think that delete is supposed to handle null pointers.

If you must store pointers to dynamically allocated memory in STL
containers (and there are reasons to do so), then you really should
write your own wrapper class that handles both allocations and deletions
itself, to ensure that no pointers to non-dynamic memory get stored, and
that everything is appropriately deleted. Also, if there's a chance of
an exception being thrown in your code, make sure that exceptions can't
result in memory leaks.

Rennie deGraaf
 
M

mlimber

Rennie said:
kathy said:
I am using std::vector in my program:

func()
{
std::vector <CMyClass *> vpMyClass;
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());

//???? Required ??????????????//
delete vpMyClass[0];
delete vpMyClass[1];
delete vpMyClass[2];

}

or vector automatically delete all pointer when it is out of the scope?

Vector just knows about the value that it's storing - a binary value of
the size of memory addresses on your system. It doesn't know or care
about what that value actually means. So, yes, if you store pointers to
dynamically allocated memory in a vector, you are responsible for
freeing the memory yourself. [snip]
If you must store pointers to dynamically allocated memory in STL
containers (and there are reasons to do so), then you really should
write your own wrapper class that handles both allocations and deletions
itself, to ensure that no pointers to non-dynamic memory get stored, and
that everything is appropriately deleted. Also, if there's a chance of
an exception being thrown in your code, make sure that exceptions can't
result in memory leaks.

Rennie deGraaf

Another option is to use a canned smart pointer instead of a raw
pointer to wrap them. Consider boost::shared_ptr, which is also part of
TR1, the proposed extensions to the standard library:

http://boost.org/libs/smart_ptr/smart_ptr.htm

The OP's code would then look like:

#include <boost/shared_ptr.hpp>

void func()
{
std::vector< boost::shared_ptr<CMyClass> > vpMyClass;
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());

// No delete needed
}


Cheers! --M
 
B

Ben Pope

kathy said:
I am using std::vector in my program:

func()
{
std::vector <CMyClass *> vpMyClass;
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());

//???? Required ??????????????//
delete vpMyClass[0];
delete vpMyClass[1];
delete vpMyClass[2];

}

You need to do this since *you* used new, *you* must use delete.
or vector automatically delete all pointer when it is out of the scope?

It frees the memory required for the pointer, but not the memory the
pointer points to.

There may be a problem though, consider:

func() {
std::vector <CMyClass *> vpMyClass;
vpMyClass.push_back(new CMyClass());

// Do something that throws an exception

// this statement not reached, memory leaked.
delete vpMyClass[0];
}

An oft-used solution is to use boost::shared_ptr:

#include <vector>
#include <boost/shared_ptr.hpp>

class CMyClass {};

typedef boost::shared_ptr<CMyClass> spMyClass;

void func() {
std::vector <spMyClass> vpMyClass;
vpMyClass.push_back(spMyClass(new CMyClass()));

// Do something that may throw an exception

//don't need to worry about cleanup, shared_ptr does it.
}

int main() {
func();
}


If you want the container to manage the lifetime, then you can take a
look at boost pointer conatiners:
http://www.boost.org/libs/ptr_container/doc/ptr_vector.html

This will allow your original syntax for adding to the vector:

boost::ptr_vector<CMyClass> vpMyClass;
vpMyClass.push_back(new CMyClass());


Have fun!

Ben Pope
 
J

Jeff Lefebvre

A nice way to free the memory dynamically allocated in your vector is
described in "Effective C++, second edition" from Meyers:

struct DeleteObject
{
template<typename T>
void operator()(const T* ptr) const
{
delete ptr;
ptr = 0L;
}
};

void func()
{
std::vector <CMyClass *> vpMyClass;
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());

for_each(vpMyClass.begin(), vpMyClass.end(), DeleteObject());
}

It works for any type!
 
A

Axter

Ben said:
kathy said:
I am using std::vector in my program:

func()
{
std::vector <CMyClass *> vpMyClass;
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());

//???? Required ??????????????//
delete vpMyClass[0];
delete vpMyClass[1];
delete vpMyClass[2];

}

You need to do this since *you* used new, *you* must use delete.
or vector automatically delete all pointer when it is out of the scope?

It frees the memory required for the pointer, but not the memory the
pointer points to.

There may be a problem though, consider:

func() {
std::vector <CMyClass *> vpMyClass;
vpMyClass.push_back(new CMyClass());

// Do something that throws an exception

// this statement not reached, memory leaked.
delete vpMyClass[0];
}

An oft-used solution is to use boost::shared_ptr:

#include <vector>
#include <boost/shared_ptr.hpp>

class CMyClass {};

typedef boost::shared_ptr<CMyClass> spMyClass;

void func() {
std::vector <spMyClass> vpMyClass;
vpMyClass.push_back(spMyClass(new CMyClass()));

// Do something that may throw an exception

//don't need to worry about cleanup, shared_ptr does it.
}

int main() {
func();
}


If you want the container to manage the lifetime, then you can take a
look at boost pointer conatiners:
http://www.boost.org/libs/ptr_container/doc/ptr_vector.html

This will allow your original syntax for adding to the vector:

boost::ptr_vector<CMyClass> vpMyClass;
vpMyClass.push_back(new CMyClass());

For a more generic method, you can use cow_ptr and/or copy_ptr smart
pointers.
http://code.axter.com/cow_ptr.h
http://code.axter.com/copy_ptr.h

Both of the above smart pointers can be used without having to create a
clone function, where as the boost pointer containers require
additional clone function logic in order to use it.
Also, (IMO) the cow_ptr/copy_ptr smart pointers are better at catching
slicing then are the boost pointer containers.
Example usage:
vector<cow_ptr<CMyClass> > vpMyClass;
vpMyClass.push_back(new CMyClass);
 
A

Axter

Jeff said:
A nice way to free the memory dynamically allocated in your vector is
described in "Effective C++, second edition" from Meyers:

struct DeleteObject
{
template<typename T>
void operator()(const T* ptr) const
{
delete ptr;
ptr = 0L;
}
};

void func()
{
std::vector <CMyClass *> vpMyClass;
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());

for_each(vpMyClass.begin(), vpMyClass.end(), DeleteObject());
}

It works for any type!
I recommend a DeleteObject class that will also Nullify the pointer.
Example code:
class DeleteObject
{
public:
template<typename T>
bool operator()(T& ptr)
{
delete &*ptr;
ptr = NULL;
return true;
}
};

Example usage:
vpMyClass.erase(remove_if(vpMyClass.begin(),
vpMyClass.end(),DeleteObject()), vpMyClass.end());

The above DeleteObject class will also work with any object, and using
the above method would delete and remove the objects from the vector
all in one line of code.
 
J

Jim Langston

Rennie deGraaf said:
kathy said:
I am using std::vector in my program:

func()
{
std::vector <CMyClass *> vpMyClass;
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());

//???? Required ??????????????//
delete vpMyClass[0];
delete vpMyClass[1];
delete vpMyClass[2];

}

or vector automatically delete all pointer when it is out of the scope?

Vector just knows about the value that it's storing - a binary value of
the size of memory addresses on your system. It doesn't know or care
about what that value actually means. So, yes, if you store pointers to
dynamically allocated memory in a vector, you are responsible for
freeing the memory yourself.

Another perspective: If vectors containing pointers somehow knew to free
dynamically allocated objects before deleting the entries, then the
following code would probably crash your system:

func()
{
std::vector<char*> vec;
vec.push_back("a string");
vec.push_back(new char[100]);
vec.push_back(NULL);
}

The second thing that I push is a pointer to dynamically-allocated
memory that must be freed. The first, however, is a pointer to
statically-allocated memory, and attempting to delete it would result in
undefined behaviour. The third points to nothing at all, although I
think that delete is supposed to handle null pointers.

If you must store pointers to dynamically allocated memory in STL
containers (and there are reasons to do so), then you really should
write your own wrapper class that handles both allocations and deletions
itself, to ensure that no pointers to non-dynamic memory get stored, and
that everything is appropriately deleted. Also, if there's a chance of
an exception being thrown in your code, make sure that exceptions can't
result in memory leaks.

Rennie deGraaf

Please explain this wrapper class you are talking about that handles both
allocations and deletions itself.

I use a lot of vectors or maps of pointers in my program(s). What would
this wrapper class do?

Oh, I think I understand. Instead of storing the pointer to char just store
the wrapper class.

class MyWrapper
{
public:
MyClass *MyObject;
MyWrapper() { MyObject = new MyClass }
~MyWrapper() { delete MyObject; }
};

std::vector <MyWrapper> MyVector;

Interesting. This is a good thought and I think I might implement this.
Then I don't have to iterate and delete the objects of my vector when it
goes out of scope/gets deleted itself.
 
R

Rennie deGraaf

Jim said:
kathy said:
I am using std::vector in my program:

func()
{
std::vector <CMyClass *> vpMyClass;
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());

//???? Required ??????????????//
delete vpMyClass[0];
delete vpMyClass[1];
delete vpMyClass[2];

}

or vector automatically delete all pointer when it is out of the scope?

Vector just knows about the value that it's storing - a binary value of
the size of memory addresses on your system. It doesn't know or care
about what that value actually means. So, yes, if you store pointers to
dynamically allocated memory in a vector, you are responsible for
freeing the memory yourself.

Another perspective: If vectors containing pointers somehow knew to free
dynamically allocated objects before deleting the entries, then the
following code would probably crash your system:

func()
{
std::vector<char*> vec;
vec.push_back("a string");
vec.push_back(new char[100]);
vec.push_back(NULL);
}

The second thing that I push is a pointer to dynamically-allocated
memory that must be freed. The first, however, is a pointer to
statically-allocated memory, and attempting to delete it would result in
undefined behaviour. The third points to nothing at all, although I
think that delete is supposed to handle null pointers.

If you must store pointers to dynamically allocated memory in STL
containers (and there are reasons to do so), then you really should
write your own wrapper class that handles both allocations and deletions
itself, to ensure that no pointers to non-dynamic memory get stored, and
that everything is appropriately deleted. Also, if there's a chance of
an exception being thrown in your code, make sure that exceptions can't
result in memory leaks.

Rennie deGraaf


Please explain this wrapper class you are talking about that handles both
allocations and deletions itself.

There's no easy way (using standard C++) to store objects of different
types derived from the same base class in an STL container. One common
work-around is to store pointers to the base class in the container. If
you must do this, then I reccomend that you wrap your container in a
class that makes copies of objects to insert, returns const references
to objects, deletes everything properly in its destructor, and is very
careful about exceptions. For instance, if I have the following classes:

class Shape;
class Circle : public Shape;
class Square : public Shape;

and you needed to store both Circles and Squares in the same
std::vector, then you could do something like this:

class ShapeVector {
std::vector<Shape*> shapes;
public:
const Shape& getFirst() { return *(shapes[0]); }
void add(Shape& shape) { shapes.push_back(new Shape(shape)); }
~ShapeVector() { for (int i=0; i<shapes.length(); i++) delete
shape; }

This is incomplete and probably won't compile, but hopefully you get the
idea. If it's possible for any of your methods that allocate or free
resources to throw exceptions, make sure that nothing is left hanging
when an exception is thrown.

(For the record, there are apparently ways to solve the problem that I
described without using pointers, by using classes from boost.)

If you're storing objects by pointer because you can't afford the cost
of the STL copying them all the time, you might still use a trick like
this, as long as you can afford the cost of copying them once.

An alternate approach, that may be better in some situations, would be
to use some sort of smart pointer. This would work even if you can't
afford to copy your objects at all, or they aren't copyable. If you're
not trying to use polymorphism, and your objects are cheaply copyable,
them I can't think of any good reason to store pointers to dynamic
memory in a container.

I use a lot of vectors or maps of pointers in my program(s). What would
this wrapper class do?

Oh, I think I understand. Instead of storing the pointer to char just store
the wrapper class.

class MyWrapper
{
public:
MyClass *MyObject;
MyWrapper() { MyObject = new MyClass }
~MyWrapper() { delete MyObject; }
};

std::vector <MyWrapper> MyVector;

Interesting. This is a good thought and I think I might implement this.
Then I don't have to iterate and delete the objects of my vector when it
goes out of scope/gets deleted itself.

This would be a good approach for expensively copyable or uncopyable
objects. Don't bother for cheaply copiable stuff - just store them
directly.

Rennie deGraaf
 
J

Jim Langston

Rennie deGraaf said:
Jim said:
kathy wrote:

I am using std::vector in my program:

func()
{
std::vector <CMyClass *> vpMyClass;
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());
vpMyClass.push_back(new CMyClass());

//???? Required ??????????????//
delete vpMyClass[0];
delete vpMyClass[1];
delete vpMyClass[2];

}

or vector automatically delete all pointer when it is out of the scope?


Vector just knows about the value that it's storing - a binary value of
the size of memory addresses on your system. It doesn't know or care
about what that value actually means. So, yes, if you store pointers to
dynamically allocated memory in a vector, you are responsible for
freeing the memory yourself.

Another perspective: If vectors containing pointers somehow knew to free
dynamically allocated objects before deleting the entries, then the
following code would probably crash your system:

func()
{
std::vector<char*> vec;
vec.push_back("a string");
vec.push_back(new char[100]);
vec.push_back(NULL);
}

The second thing that I push is a pointer to dynamically-allocated
memory that must be freed. The first, however, is a pointer to
statically-allocated memory, and attempting to delete it would result in
undefined behaviour. The third points to nothing at all, although I
think that delete is supposed to handle null pointers.

If you must store pointers to dynamically allocated memory in STL
containers (and there are reasons to do so), then you really should
write your own wrapper class that handles both allocations and deletions
itself, to ensure that no pointers to non-dynamic memory get stored, and
that everything is appropriately deleted. Also, if there's a chance of
an exception being thrown in your code, make sure that exceptions can't
result in memory leaks.

Rennie deGraaf


Please explain this wrapper class you are talking about that handles both
allocations and deletions itself.

There's no easy way (using standard C++) to store objects of different
types derived from the same base class in an STL container. One common
work-around is to store pointers to the base class in the container. If
you must do this, then I reccomend that you wrap your container in a
class that makes copies of objects to insert, returns const references
to objects, deletes everything properly in its destructor, and is very
careful about exceptions. For instance, if I have the following classes:

class Shape;
class Circle : public Shape;
class Square : public Shape;

and you needed to store both Circles and Squares in the same
std::vector, then you could do something like this:

class ShapeVector {
std::vector<Shape*> shapes;
public:
const Shape& getFirst() { return *(shapes[0]); }
void add(Shape& shape) { shapes.push_back(new Shape(shape)); }
~ShapeVector() { for (int i=0; i<shapes.length(); i++) delete
shape; }

This is incomplete and probably won't compile, but hopefully you get the
idea. If it's possible for any of your methods that allocate or free
resources to throw exceptions, make sure that nothing is left hanging
when an exception is thrown.

(For the record, there are apparently ways to solve the problem that I
described without using pointers, by using classes from boost.)

If you're storing objects by pointer because you can't afford the cost
of the STL copying them all the time, you might still use a trick like
this, as long as you can afford the cost of copying them once.

An alternate approach, that may be better in some situations, would be
to use some sort of smart pointer. This would work even if you can't
afford to copy your objects at all, or they aren't copyable. If you're
not trying to use polymorphism, and your objects are cheaply copyable,
them I can't think of any good reason to store pointers to dynamic
memory in a container.

I use a lot of vectors or maps of pointers in my program(s). What would
this wrapper class do?

Oh, I think I understand. Instead of storing the pointer to char just
store
the wrapper class.

class MyWrapper
{
public:
MyClass *MyObject;
MyWrapper() { MyObject = new MyClass }
~MyWrapper() { delete MyObject; }
};

std::vector <MyWrapper> MyVector;

Interesting. This is a good thought and I think I might implement this.
Then I don't have to iterate and delete the objects of my vector when it
goes out of scope/gets deleted itself.

This would be a good approach for expensively copyable or uncopyable
objects. Don't bother for cheaply copiable stuff - just store them
directly.


Actually, I store vectors of pointers for 2 different reasons.
The first one is polymorphism.
The second one is becuase I'm using a header to a dll that has objects I
want to store that don't follow the rule of three and aren't copyable.
Hence I store the pointers.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,430
Messages
2,571,676
Members
48,796
Latest member
Greg L.

Latest Threads

Top