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:
- "Whole-object" vector member varaiable containing values, i.e.
vector<MyClass> my_vector;
- Pointer to a vector, i.e
vector<MyClass>* my_vector;
- Vector of pointers, i.e.
vector<MyClass*> my_vector;
- 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!!
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.
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.
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.
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:
- If the vector owns the objects (that means their lifetime is bounded by that of the vector), you could use a
boost::ptr_vector
. - If the objects are not owned by the vector, you could either use a vector of
boost::shared_ptr
, or a vector ofboost::ref
.
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.
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...
精彩评论