user2116010
user2116010

Reputation: 211

How to add an element into the vector of pointers?

I have this:

std::vector <BinaryTree*> children;

where BinaryTree is a class. How can I add an element into this vector?

I tried children.push_back(X) where X is an instance of the class but it gives me this error:

cannot convert parameter 1 from 'BinaryTree' to 'BinaryTree *&&'

Upvotes: 4

Views: 23457

Answers (8)

LihO
LihO

Reputation: 42083

You have vector of pointers:

std::vector <BinaryTree*> children;

so the proper way of adding elements is:

BinaryTree* child = new BinaryTree();
children.push_back(child);

just be careful while doing something like this:

{
    BinaryTree child;
    children.push_back(&child);
}

because lifetime of such an element might be shorter than lifetime of the vector and you might end up trying to access an element that no longer exists (dangling pointer) which produces undefined behavior. Also don't forget to delete these elements when done with it.

But it's always good to consider using vector of objects first (i.e.std::vector<BinaryTree>) since that would take care of that ugly memory management for you.

Upvotes: 0

Andy Prowl
Andy Prowl

Reputation: 126412

Just use the push_back() and pass a pointer to an instance of BinaryTree:

std::vector <BinaryTree*> children;
BinaryTree* pTree = new BinaryTree();
children.push_back(pTree);
...
delete pTree;

In order to avoid manual memory management, if you need reference semantics, use smart pointers instead of raw pointers:

#include <memory> // For std::shared_ptr

std::vector <std::shared_ptr<BinaryTree>> children;
std::shared_ptr<BinaryTree> pTree = std::make_shared<BinaryTree>();
children.push_back(pTree);
...
// No need to delete pTree

The std::shared_ptr<> class template is part of the C++11 Standard Library. In C++03, you could use the (almost) equivalent boost::shared_ptr<>:

#include <boost/shared_ptr.hpp> // For std::shared_ptr

std::vector <boost::shared_ptr<BinaryTree>> children;
boost::shared_ptr<BinaryTree> pTree = boost::make_shared<BinaryTree>();
children.push_back(pTree);
...
// No need to delete pTree

Finally, if you do not need reference semantics at all and want to treat your binary trees as values instead, you can even consider defining a std::vector<BinaryTree>:

std::vector<BinaryTree> children;
BinaryTree tree;
children.push_back(tree);

Upvotes: 11

juanchopanza
juanchopanza

Reputation: 227370

It really depends on who is supposed to own the pointers. In the simplest case, where the vector doesn't own them, then you pass the address of a BinaryTree object.

BinaryTree b = ...;
children.push_back(&b);

But you have to be sure b lives at least as long as children does.

If the vector owns the pointers, then you should probably store smart pointers to avoid having to deal with memory managemen:

std::vector<std::unique_ptr<BinaryTree>> children;
children.push_back(std::unique_ptr<BinaryTree>(new BinaryTree(args)));

If you don't know what all this "ownership" business means, then you are most likely better off with a plain vector of objects:

std::vector<BinaryTree> children;

Upvotes: 3

Praetorian
Praetorian

Reputation: 109089

The vector contains pointers to objects of type BinaryTree. You need

BinaryTree bt;
children.push_back( &bt );

But you must ensure that the lifetime of the bt object at least matches that of the vector.

You may want this instead

children.push_back( new BinaryTree );

But in this case you must call delete on the pointer contained in the vector to prevent a memory leak.

As evident, neither option is easy to manage. An easy change is to make your container store the elements by value.

std::vector<BinaryTree> children;
BinaryTree bt;
children.push_back( bt );

If you must store pointers, use a smart pointer to hold them instead.

std::vector<std::unique_ptr<BinaryTree>> children;
children.push_back( new BinaryTree );

Now you don't need to worry about deleting the objects before emptying the vector.

Upvotes: 0

Kijewski
Kijewski

Reputation: 26022

Omit the asterisk * from the template argument:

std::vector<BinaryTree> children;

You want children to hold the data, without manual/dynamic memory allocation as in new BinaryTree.

Upvotes: 3

David Tr
David Tr

Reputation: 151

children.push_back(&X);

Pass the address as if you were using it as a pointer. But the problem then is if that instance goes out of scope, so better to do this

BinaryTree* X = new BinaryTree;
children.push_back(X);

This will ensure that X never goes out of scope, but then you have to manually delete it when you're finished with it.

Upvotes: 0

jt234
jt234

Reputation: 672

children.push_back(&X);

This will work but bear in mind that once your object leaves scope, its deleter will be called and you will be left with an invalid pointer.

Upvotes: 0

Floris Velleman
Floris Velleman

Reputation: 4888

std::vector<SomeObject*> objectVector;
objectVector.push_back(new SomeObject());

Is how I do it.

Upvotes: 1

Related Questions