Can one store pointers to auto_ptr(s) in a std::vector? Is it safe?
I enumerate a folder reading in XML files and creating an object for each with auto_ptr. I don't know in advance how many XML files there will be and I'd like to use a vector to essentially keep a list of pointers to them.
I'm also assuming that when a pointers are removed from the Vector (or the vector is destroyed) the pointers are pretty much gone, so I wouldn't have to worry about setting them to NULL.
You can't store an auto_ptr itself in a std::vector, but storing a plain pointer is fine, even if the thing it points to is an auto_ptr.
I don't see why you'd want to do that, though. The whole point of auto_ptr is to ensure that heap-allocated objects are deleted automatically when they go out of scope. You lose that benefit if the auto_ptr itself has to be deleted manually.
If you want to store heap-allocated objects safely in a vector, you can use std::tr1::shared_ptr instead of auto_ptr, or use Boost's pointer containers. Or, if you're using C++11, std::unique_ptr is like std::auto_ptr except it's safe to use in containers.
Yes you could - but it is totally unsafe and will do all sorts of unexpected things that will surprise you.
If you want to store smart pointers in a container have a look at unique_ptr if your compiler supports C++11 stuff
Related
Assuming that my T is a vector typedef std::vector<ofSomething> T; ( it's usually a vector around 4-5 MB, it's expensive to recreate and store as it is in a data structure )
so, considering :
pointers
references
smart pointers
I have to create a container of vectors, or I have to put all this vectors together somehow, I'm wondering what is the best approach according to the RAII philosophy .
std::container<T*>
or
std::container<T&>
or
std::container<unique_ptr<T>>
with pointers I need to call the destructor explicitly, and this doesn't really look and sound like RAII at all.
with references it's basically the same as with pointers.
with smart pointers I get what I want if I delete or just "drop" the object representing the smart pointer.
Is a collection of smart pointers a really good idea for a container of containers ? I don't know, they are here to express ownership not for automatic memory management, it sounds like I'm doing something wrong with the wrong philosophy, at the same time I have multiple big containers to handle until they "expire" or they are not needed anymore.
What you suggest ?
If you want a vector of vectors, and you want RAII, then the answer is so simple:
std::vector<std::vector<T>> v;
… no references or pointers in sight.
If you're concerned about the inner containers being moved around as the outer vector grows, flatten it:
std::vector<T>
and wrap the indexing, so that i = x*W+y.
As you say, with a raw pointer you'll need to do your own memory management - scratch that. You can't store a reference in a standard container because allocators are not defined for reference types, and you'll still need to allocate your objects on the heap somehow - scratch that. The std::unique_ptr will perform memory management for you and actually compile - this wins... from your choices.
But what about std::container<T>? This will also work fine and not have any issues with manual memory management. It will also benefit from move semantics, so you don't need to worry about the vectors being copied. You also avoid an extra level of indirection.
Obviously using a std::unique_ptr restricts what you can do with your container. If you need to be able to copy it and/or its items, you'll want std::shared_ptr instead.
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 of boost::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...
I've been looking for a way to do safe vectors and maps of dynamic pointers, when I realized C++11 adds unique_ptrs. I looked into how to use them on Google, but have been unsuccessful in looking for details. What I need to know are the following:
What, exactly, is different between pointers and unique_ptrs besides automatic memory collection?
How would I go about removing a unique_ptr from a vector or map? Is there any special code I have to use besides erasing the iterator?
Nothing. A unique_ptr is just a wrapper around a pointer, which deletes the pointer when the unique_ptr is destroyed. It has no overhead (just like the auto_ptr template it replaces).
Nope -- it will just work. The difficulty actually comes from inserting the pointer into the vector or map -- whereas you must move the unique_ptr into the container.
The difference is that unique_ptr obeys move semantics. Further, as the name suggests, you can't make copies of it.
Erasing an element of std::vector<std::unique_ptr<T> > will effectively delete whatever that pointer pointed at.
I just discovered the concept of an auto_ptr and am liking it! As Qt often requires a QList or QVector<(some QObject or QWidget) *>, is there any concrete reason why auto_ptr should be avoided. If I'm right, it allows you to replace this:
std::vector<MyClass*> vec;
/* add several elements to the vector and do stuff with them */
for(size_t i=0; i<vec.length(); ++i)
{
delete vec[i];
}
vec.clear();
with somthing much shorter (ie no cleanup)
std::vector<auto_ptr<MyClass>> vec;
/* add several elements to the vector and do stuff with them */
// no need for the delete loop
...Can Qt still work its shared memory magic with auto_ptr's? Does the parent-child automagic memory management still function transparently? Thanks
Qt has its own smart pointer classes that are in many ways superior to std::auto_ptr, specifically in that some of them can be put into containers with no issues. std::auto_ptr has ownership-transfer copy semantics, and so will not work as expected if you try to put it into a container.
Try using QSharedPointer. It's a reference counted smart pointer that deletes its contained object when there are no more copies of the smart pointer left. Unlike std::auto_ptr there can be multiple copies of the same QSharedPointer at once, and therefore it plays well with containers.
If you want a container that has ownership of pointers then look at boost pointer containers.
You put pointers into the container, but like the other containers they are then treated like normal objects which makes it easier to use them with standard algorithms (i.e. no need to write wrapper classes). When the pointer container goes out of scope it will call delete on all pointers in the container:
boost::ptr_vector<MyClass> v;
v.push_back(new MyClass(12));
std::for_each(v.begin(), v.end(), DoStuff());
// Destroyed here.
std::auto_ptr cannot be used in std::vector, because std::vector expects to be able to copy its contents, and you can't copy a std::auto_ptr in the normal sense. Copying means winding up with two identical things, and if you had two identical std::auto_ptrs what they pointed to would be double-freed when they went out of scope. (What happens instead is that the auto_ptr being copied from has its internal pointer zeroed out, and the one being copied to is now what the old one used to be.)
Use shared_ptr, which is often available as boost::shared_ptr or on Visual C++ std::tr1::shared_ptr, and which will be in the C++0x standard library, or use whatever Qt has. Those can be copied, and therefore can go into containers.
How is the destructor for the vector managed when adding elements to this list? Is the object destroyed correctly when it goes out of scope? Are there cases where it would not delete the object correctly? For example what are the consequences if "table" was a child of object, and we added a new table to a vector of object pointers?
vector <object*> _objectList;
_objectList.PushBack(new object);
Since you're making a vector of "bare" pointers, C++ can't possibly know that the pointers in question are meant to have "ownership" of the objects they point to, and so it will not call those objects' destructors when the pointer goes away. You should use a simple "smart" pointer instead of a "bare" pointer as the vector's item. For example, Boost's shared_ptr would be perfectly adequate for the task (although you can surely do it with "cheaper", lighter-weight approaches, if you don't want to deal with Boost as a whole and have no other need for smart pointers in your code).
Edit: since you (the OP) say that using a framework such as Boost is not feasible, and a couple comments usefully point out that even wrapping std::auto_ptr doesn't really qualify as a decent shortcut, you may have to implement your own smart pointers (or, if you find an open-source, stand-alone smart pointer template class that looks usable, audit it for compliance with your requirements). This article is a useful primer to smart pointers in C++, whether you have to roll your own or audit an existing implementation.
You could use bost 'ptr_vector'. It will automatically destruct objects that the items point to when they are either deleted or the instance of ptr_vector goes out of scope. More info is available here.
In your case, the object pointers are destroyed properly, but the actual objects themselves won't be touched. The STL properly destructs all contained elements - but will not implicitly dereference pointers to types.
STL Vectors make a copy of whatever you put in there, and ultimately delete that copy.
So in this case, the vector is storing a pointer to an object - not the object itself. So it makes a copy of the pointer, and deletes the pointer. But, as Chris said, the object itself will not be deleted.
So, solutions:
If you don't really need to use pointers, then don't:
vector <object> _objectList;
_objectList.PushBack(object());
If you do need to use pointers, you can either use a smart pointer (which handles reference counting for you, and will delete the object along with the pointer), as Alex suggested, or use a ptr_vector, as Igor mentioned.