13

Just wondering what you think is the best practice regarding vectors in C++.

If I have a class containing a vector member variable. When should this vector be declared a:

  1. "Whole-object" vector member varaiable containing values, i.e. vector<MyClass> my_vector;
  2. Pointer to a vector, i.e vector<MyClass>* my_vector;
  3. Vector of pointers, i.e. vector<MyClass*> my_vector;
  4. Pointer to vector of pointers, i.e. vector<MyClass*>* my_vector;

I have a specific example in one of my classes where I have currently declared a vector as case 4, i.e. vector<AnotherClass*>* my_vector; where AnotherClass is another of the classes I have created.

Then, in the initialization list of my constructor, I create the vector using new:

MyClass::MyClass()
: my_vector(new vector<AnotherClass*>())
{}

In my destructor I do the following:

MyClass::~MyClass()
{
  for (int i=my_vector->size(); i>0; i--)
  {
    delete my_vector->at(i-1);
  }
  delete my_vector;
}

The elements of the vectors are added in one of the methods of my class. I cannot know how many objects will be added to my vector in advance. That is decided when the code executes, based on parsing an xml-file.

Is this good practice? Or should the vector instead be declared as one of the other cases 1, 2 or 3 ?

When to use which case?

I know the elements of a vector should be pointers if they are subclasses of another class (polymorphism). But should pointers be used in any other cases ?

Thank you very much!!

Lisa
  • 139
  • 1
  • 1
  • 3

6 Answers6

4

Usually solution 1 is what you want since it’s the simplest in C++: you don’t have to take care of managing the memory, C++ does all that for you (for example you wouldn’t need to provide any destructor then).

There are specific cases where this doesn’t work (most notably when working with polymorphous objects) but in general this is the only good way.

Even when working with polymorphous objects or when you need heap allocated objects (for whatever reason) raw pointers are almost never a good idea. Instead, use a smart pointer or container of smart pointers. Modern C++ compilers provide shared_ptr from the upcoming C++ standard. If you’re using a compiler that doesn’t yet have that, you can use the implementation from Boost.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 3
    I wonder why people never mention `Boost.Pointer Container` or `Boost.Reference` in this context. – Björn Pollex Apr 13 '11 at 12:13
  • @Space I have, of sorts: “use a smart pointer *or container of smart pointers*.” I’ve never used them though so I don’t feel very confident to talk about their benefits. – Konrad Rudolph Apr 13 '11 at 12:21
  • @Konrad: "...raw pointers (within containers) are almost never a good idea". Just curious - besides the (manual) memory management aspect of using raw pointers within containers are there any other reasons for not using raw pointers in a container? I vaguely recall there being a reason along the lines of: "As containers (say a vector), grow/shrink they may allocate/deallocate/copy/move their contents which could cause problems/undesirable side-effects if their contents are raw pointers to objects versus say a shared_ptr to objects." Is this accurate/correct? – decimus phostle Apr 13 '11 at 13:18
  • @decimus Isn’t that enough of a reason? I don’t think the reason you have mentioned is entirely accurate. Pointers themselves can be copied and moved without any problems. This only gets tricky when the object needs to *manage* those pointers since then you need to provide appropriate copy and assignment semantics. – Konrad Rudolph Apr 13 '11 at 13:27
  • `for example you wouldn’t need to provide any destructor then` Is that correct? The vector itself is not deleted, in which case you will have memory leak. You should still make a destructor and say `delete theVector` – Everyone Apr 01 '17 at 08:01
  • @Everyone That's incorrect. You can only delete pointers, and you must only delete pointers whose pointee was allocated by `new`. A vector isn't a pointer so none of this applies here. – Konrad Rudolph Apr 01 '17 at 09:02
  • @KonradRudolph Sorry I thought you were talking about this one `vector* my_vector;` and I just noticed you were talking about the traditional one without any pointer stuff. My bad – Everyone Apr 01 '17 at 09:06
1

Definitely the first!

You use vector for its automatic memory management. Using a raw pointer to a vector means you don't get automatic memory management anymore, which does not make sense.

As for the value type: all containers basically assume value-like semantics. Again, you'd have to do memory management when using pointers, and it's vector's purpose to do that for you. This is also described in item 79 from the book C++ Coding Standards. If you need to use shared ownership or "weak" links, use the appropriate smart pointer instead.

ltjax
  • 15,837
  • 3
  • 39
  • 62
0

Deleting all elements in a vector manually is an anti-pattern and violates the RAII idiom in C++. So if you have to store pointers to objects in a vector, better use a 'smart pointer' (for example boost::shared_ptr) to facilitate resource destructions. boost::shared_ptr for example calls delete automatically when the last reference to an object is destroyed.

There is also no need to allocate MyClass::my_vector using new. A simple solution would be:

class MyClass {

   std::vector<whatever> m_vector;
};

Assuming whatever is a smart pointer type, there is no extra work to be done. That's it, all resources are automatically destroyed when the lifetime of a MyClass instance ends.

In many cases you can even use a plain std::vector<MyClass> - that's when the objects in the vector are safe to copy.

Alexander Gessler
  • 45,603
  • 7
  • 82
  • 122
  • when you say "Deleting all elements in a vector manually" do you mean **not** in the destructor? From wikipedia[link](http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) "..and released with the destruction of the same objects, which is guaranteed to take place even in case of errors." Does this mean if you delete elements in a vector w/in the destuctor then you are not violating RAII? – tir38 Apr 26 '13 at 19:15
0

In your example, the vector is created when the object is created, and it is destroyed when the object is destroyed. This is exactly the behavior you get when making the vector a normal member of the class.

Also, in your current approach, you will run into problems when making copies of your object. By default, a pointer would result in a flat copy, meaning all copies of the object would share the same vector. This is the reason why, if you manually manage resources, you usually need The Big Three.

A vector of pointers is useful in cases of polymorphic objects, but there are alternatives you should consider:

  1. If the vector owns the objects (that means their lifetime is bounded by that of the vector), you could use a boost::ptr_vector.
  2. If the objects are not owned by the vector, you could either use a vector of boost::shared_ptr, or a vector of boost::ref.
Community
  • 1
  • 1
Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
-1

A pointer to a vector is very rarely useful - a vector is cheap to construct and destruct.

For elements in the vector, there's no correct answer. How often does the vector change? How much does it cost to copy-construct the elements in the vector? Do other containers have references or pointers to the vector elements?

As a rule of thumb, I'd go with no pointers until you see or measure that the copying of your classes is expensive. And of course the case you mentioned, where you store various subclasses of a base class in the vector, will require pointers.

A reference counting smart pointer like boost::shared_ptr will likely be the best choice if your design would otherwise require you to use pointers as vector elements.

Erik
  • 88,732
  • 13
  • 198
  • 189
  • So in my example, if _AnotherClass_ is a big class with lots of member variables, it could be a good idea to store these elements as pointers in the vector? To avoid copying big objects. – Lisa Apr 13 '11 at 12:08
  • 1
    @Lisa: Exactly. The correct answer cannot be anything but "it depends". – Erik Apr 13 '11 at 12:08
  • Can you elaborate on the first point - "A pointer to a vector is very rarely useful - a vector is cheap to construct and destruct." How so? – dmonopoly Feb 12 '18 at 23:11
-1

Complex answer : it depends.

if your vector is shared or has a lifecycle different from the class which embeds it, it might be better to keep it as a pointer. If the objects you're referencing have no (or have expensive) copy constructors , then it's better to keep a vector of pointer. In the contrary, if your objects use shallow copy, using vector of objects prevent you from leaking...

Bruce
  • 7,094
  • 1
  • 25
  • 42