Qt and auto_ptr - c++

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.

Related

Why is using vector of pointers considered bad?

Recently I've met with opinion that I shouldn't use vector of pointers.
I wanted to know - why I cant?
For example if I have a class foo it is possible to do this:
vector <foo*> v;
v.push_back(new foo());
I've already seen some people down voting such practices, why is that?
Storing plain pointers in a container can lead to memory leaks and dangling pointers. Storing a pointer in a container does not define any kind of ownership of the pointer. Thus the container does not know the semantics of desctruction and copy operations. When the elements are being removed from the container the container is not aware how to properly destroy them, when a copy operation is performend no ownership semanctics are known. Of course, you can always handle these things by yourself, but then still a chance of human error is possible.
Using smart pointers leaves the ownership and destruction semantics up to them.
Another thing to mention is that containers are divided into non-intrusive and intrusive contaiers - they store the actual provided object instead of a copy so it actually comes down to a collection of pointers. Non intrusive pointers have some advantages, so you can't generalize that pointers in a container is something that should be avoided in all times, still in most cases it is recommended.
Using an vector of raw pointers is not necessary bad style, as long as you remember that the pointers do not have ownership semantics. When you start using new and delete, it usually means that you're doing something wrong.
In particular, the only cases where you should use new or delete in modern C++ code is when constructing unique_ptr's, or constructing shared_ptr's with custom deleters.
For example, assume that we have an class that implemented an bidirectional Graph, a Graph contains some amount of Vertexes.
class Vertex
{
public:
Vertex();
// raw pointer. No ownership
std::vector<Vertex *> edges;
}
class Graph
{
public:
Graph() {};
void addNode()
{
vertexes.push_back(new Vertex); // in C++14: prefer std::make_unique<>
}
// not shown: our Graph class implements a method to traverse over it's nodes
private:
// unique_ptr. Explicit ownership
std::vector<std::unique_ptr<Vertex>> vertexes;
}
void connect(Vertex *a, Vertex *b)
{
a->edges.push_back(b);
b->edges.push_back(a);
}
Notice how i have an vector of raw Vertex * in that Vertex class? I can do that because the lifetime of the Vertexes that it points to are managed by the class Graph. The ownership of my Vertex class is explicit from just looking at the code.
An different answer suggests using shared_ptr's. I personally dislike that approach because shared pointers, in general, make it very hard to reason about the lifetime of objects. In this particular example, shared pointers would not have worked at all because of the circular references between the Vertexes.
Because the vector's destructor won't call delete on the pointers, so it's easy to accidentally leak memory. A vector's destructor calls the destructors of all the elements in the vector, but raw pointers don't have destructors.
However, you can use a vector of smart pointers to ensure that destroying the vector will free the objects in it. vector<unique_ptr<foo>> can be used in C++11, and in C++98 with TR1 you can use vector<tr1::shared_ptr<foo>> (though shared_ptr has a slight overhead compared to a raw pointer or unique_ptr).
Boost also has a pointer container library, where the special delete-on-destruction behavior is built into the container itself so you don't need smart pointers.
One of the problems is exception-safety.
For example, suppose that somewhere an exception is thrown: in this case, the destructor of std::vector is called. But this destructor call does not delete the raw owning pointers stored in the vector. So, the resources managed by those pointers are leaked (these can be both memory resources, so you have a memory leak, but they could also be non-memory resources, e.g. sockets, OpenGL textures, etc.).
Instead, if you have a vector of smart pointers (e.g. std::vector<std::unique_ptr<Foo>>), then if the vector's destructor is called, each pointed item (safely owned by a smart pointer) in the vector is properly deleted, calling its destructor. So, the resources associated to each item ("smartly" pointed to in the vector) are properly released.
Note that vectors of observing raw pointers are fine (assuming that the lifetime of the observed items exceeeds that of the vector). The problem is with raw owning pointers.
I will talk specifically about a vector of pointers that's responsible for managing the lifetime of the pointed objects, because that's the only case where a vector of pointers is clearly a questionable choice.
There are much better alternatives. Specifically:
std::vector<std::shared_ptr<foo>> v;
and
std::vector<std::unique_ptr<foo>> v;
and
boost::ptr_vector<foo> v; // www.boost.org
The above versions tell the user how the lifetime of the objects is taken care of. Using raw pointers instead can possibly lead to the pointers being deleted either more or less than once, especially if the code is modified over time, or if exceptions become involved.
If you use an interface like ´shared_ptr´ or ´unique_ptr´, this self-documents the lifetime management for the user. When you use raw pointers you have to be clearly document how you handle the lifetime management of the objects, and hope that the right people read the documentation at the right time.
The benefits of using vectors of raw pointers are that you have more flexibility in how taking care of lifetime management, and that you can possibly get rid of some performance and space overhead.
There is absolutely no problem in using a vector of pointers. Most here are suggesting smart pointers, but I just have to say, there is no problem with using a vector of pointers without smart pointers. I do it all the time.
I agree with juanchopanza that the problem is your example is the pointers come from new foo(). In a normal completely-valid use case, you might have the objects in some other collection C, so that the objects will automatically get destroyed when C is destroyed. Then, in doing in the process of doing in-depth operations on the objects in C, you might create any number of other collections containing pointers to the objects in C. (If the other collections used object copies that would be time and memory wasteful, while collections of references is expressly forbidden.) In this use case, we never want to destroy any objects when a collection of pointers is destroyed.

Memory management and C++ container classes

I'm having some trouble using the std container classes (list, map etc.) in C++. The problem seems to be to do with removing items for the containers. I'm trying to store pointers to objects within a container, and then when I want to remove the item from the container I use either erase or remove. When I do this, does the container actually delete the object that was in the container, or simply remove the pointer from the container?
What I'm hoping is that it just removes the pointer, because I'm using the containers to group objects and and object may be in more than one group, so I don't want it to be deleted when it's removed from a container!
Thanks!
When I do this, does the container actually delete the object that was in the container, or simply remove the pointer from the container?
The latter.
... so I don't want it to be deleted when it's removed from a container!
This is in fact what happens, but I'd still like to point out std::shared_ptr, which can make pointer/container interactions a lot easier.
When I do this, does the container actually delete the object that was in the container, or simply remove the pointer from the container?
Standard Library containers do not take the responsibility of deallocating dynamic memory of pointer elements. You will have to take care of deallocating the dynamic memory yourself, If you are storing a raw pointer in the container.
This is where power of the RAII concept in C++ comes to your rescue. You can use a Smart pointer instead of raw pointers inside the container and once you do that the deallocation will be implicitly handled by the smart pointer instead of you having the overhead of explicitly handling the memory management.
There are a number of smart pointers available and I purposefully restrained myself from suggesting a particular smart pointer because it will specifically depend on the ownership and the lifetime of the object involved.Check the link and choose a appropriate smart pointer as per your requirement.
Effective STL by Scott Meyer will give you the answer about storing raw pointer in container classes.
If you don't want to use smart_pointers or other similar things, but storing raw pointer, you have to explicitly delete it if you want to clear the memory associated.
When allocating, for example a std::vector then before clearing it, you have to delete each element of it manually.
std::vector<int*> v(10;
for (int i=0; i<10; i++)
v.at(i) = new int;
wrong way
v.clear(); // !!! MEMORY LEAK
the correct way is
for (int i=0; i<10; i++)
delete v.at(i);
and then
v.clear();
comipler doesn't remove object which placed in heap-memory

storing pointers to auto_ptr in vector

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

Pointer to vector vs vector of pointers vs pointer to vector of pointers

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...

Does myVector.erase(myPtr) delete the object pointed by myPtr?

If I have the following code,
Foo *f = new Foo();
vector<Foo*> vect;
vect.push_back(f);
// do stuff
vect.erase(f);
Did I create a memory leak?
I guess so, but the word erase gives the feeling that it is deleting it.
Writing this, I am wondering if it is not a mistake to put a pointer in a STL vector. What do you think?
Yes, you created a memory leak by that. std::vector and other containers will just remove the pointer, they won't free the memory the pointer points to.
It's not unusual to put a pointer into a standard library container. The problem, however, is that you have to keep track of deleting it when removing it from the container. A better, yet simple, way to do the above, is to use boost::shared_ptr:
{
boost::shared_ptr<foo> f(new foo);
std::vector< boost::shared_ptr<foo> > v;
v.push_back(f);
v.erase(v.begin());
} /* if the last copy of foo goes out of scope, the memory is automatically freed */
The next C++ standard (called C++1x and C++0x commonly) will include std::shared_ptr. There, you will also be able to use std::unique_ptr<T> which is faster, as it doesn't allow copying. Using std::unique_ptr with containers in c++0x is similar to the ptr_container library in boost.
Another option is to use the Boost Pointer Containers. They are designed to do exactly what you want.
Alternatively there is the boost::ptr_vector container.
It knows it is holding pointers that it owns and thus auto deletes them.
As a nice side affect, when accessing elements it returns a reference to the object not the pointer to make the code look nice.
Foo *f = new Foo();
boost::ptr_vector<Foo> vect;
vect.push_back(f);
// do stuff
vect.erase(f);
To clarify why the pointer is not deleted, consider
std::vector<char const*> strings;
strings.push_back("hello");
strings.push_back("world");
// .erase should not call delete, pointers are to literals
std::vector<int*> arrays;
strings.push_back(new int[10]);
strings.push_back(new int[20]);
// .erase should call delete[] instead of delete
std::vector<unsigned char*> raw;
strings.push_back(malloc(1000));
strings.push_back(malloc(2000));
// .erase should call free() instead of delete
In general, vector<T*>::erase cannot guess how you'd dispose of a T*.
It is definitely not a mistake to point a pointer into a standard container (it's a mistake to make a container of auto_ptr's however). Yes, you do need to explicitly delete to free the memory pointed to by the individual elements, or you can use one of the boost smart pointers.
vector deletes the data it contains. Since your vector contains pointers, it only deletes the pointers, not the data they may or may not point to.
It's a pretty general rule in C++ that memory is released where it was allocated. The vector did not allocate whatever your pointers point to, so it must not release it.
You probably shouldn't store pointers in your vector in the first place.
In many cases, you would be better off with something like this:
vector<Foo> vect;
vect.push_back(Foo());
// do stuff
vect.erase(f);
Of course this assumes that Foo is copyable, and that its copy constructor is not too expensive, but it avoids memory leaks, and you don't have to remember to delete the Foo object. Another approach would be to use smart pointers (such as Boost's shared_ptr), but you may not need pointer semantics at all, in which case the simple solution is the best one.
STL containers will not free your memory. The best advice is using smart pointers, knowing that std::auto_ptr will not fit inside containers. I would recommend boost::shared_ptr, or if your compiler vendor has support for TR1 extensions (many do) you can use std::tr1::shared_ptr.
Also note that the vector will not even free the internal memory reserved for the pointer. std::vectors never downsize not even with a call to clear(). If you need to downsize a vector you will have to resort to creating another vector and swapping contents.