gfyg
gfyg

Reputation: 9

vector of pointers instead of objects

Every time you put object into std::vector it has to make a copy of that object.

So can I just put pointers instead of objects like that?:

Class *ptr_Class;
Class object;
ptr_Class = &object;

std::vector<Class*> vector;
vector.push_back(ptr_Class);

Or for some reason it is not a good idea?

Upvotes: 0

Views: 122

Answers (3)

Wyzard
Wyzard

Reputation: 34581

You can make a vector of pointers, but you have to be aware that the vector will not automatically call delete on the pointers when it's done with them. If your pointers were allocated with new, you have to delete them yourself before removing elements or destroying the vector, or you'll leak memory. It's tricky to make sure this cleanup happens in all cases; in particular, exceptions can cause cleanup code at the end of a function to be skipped.

It's safer to use a vector of smart pointers, which will take care of that cleanup automatically, even in the face of exceptions. In C++11 you can just make a vector of std::unique_ptr<T>. With older compilers that don't support C++11, you can use std::tr1::shared_ptr<T> or boost::shared_ptr<T> instead, though that has some overhead from reference-counting that you don't really need. You can't put C++98's std::auto_ptr in a vector (which is why it was deprecated and replaced with std::unique_ptr in C++11).

Also, in C++11 you have some options for avoiding the copy when inserting an object into a vector:

  • You can call myvector.push_back(std::move(myobject)) to move the object into the vector instead of copying it. This still constructs a new instance within the vector, but it's allowed to take ownership of any resources held by myobject instead of copying them. The myobject shouldn't be used afterward, since it no longer holds the data that it used to.
  • You can call myvector.emplace_back(...) to construct a new object directly into the vector's storage. This is basically a wrapper for your class's constructor, and can be given any set of arguments that are valid to pass to that constructor.

Note that if you want your vector to be polymorphic — that is, if you want to be able to store both squares and circles in a vector of shapes — then a storing pointers (preferably smart pointers) is your only option. All items actually stored within a vector must be the same type, so that type has to be something like a base-class pointer.

Upvotes: 1

mxdg
mxdg

Reputation: 314

You are not using "new", or allocating memory, so technically you won't have any memory leaks.

However, you have to be careful with scope. For instance, if you have

std::vector<Class*> funcFoo()
{
    Class *ptr_Class;
    Class object;
    ptr_Class = &object;
    std::vector<Class*> vector;
    vector.push_back(ptr_Class);
    return vector;
}

you will end up with a vector of a pointer that pointed to an object in funcFoo. That object will likely be garbage after you leave the function.

I'm assuming that what you want is more like this:

Class *ptr_Class = new Class();
std::vector<Class*> vector;
vector.push_back(ptr_Class);

If this is the case, then you have to remember to deallocate any memory you allocated with new by calling delete.

For instance:

for (unsigned int i = 0; i < vector.size(); ++i)
{
    delete vector[i];
    vector[i] = NULL; 
}

Upvotes: 1

Ed Heal
Ed Heal

Reputation: 60037

Use a vector of smart pointers. in that way you will not get memory leaks.

The method you have described you have to be careful when popping from the list and you need to ensure that the list is empty when you have finished with it.

Upvotes: 3

Related Questions