So today I learned the hard way the meaning of nsAutoPtr<>. I started to use it when I copied a piece of code from another component that did something similar to what I was doing. What I didn’t realize was the true purpose of nsAutoPtr<> which lead to a… shall we say crash in Fennec!

I (wrongly) assumed it was some magic kind of pointer that you could assign to and use as a normal pointer, well you can – if you know how it’s supposed to work.

I imagine that nsAutoPtr was created to assist the developers in preventing one of the common mistakes, namly to forget to release (delete) an object that has been created (new’ed) dynamically. It is however very bad when you try to store pointers to the object in multiple places.

Let me first explain how I now understand how to use nsAutoPtr<>. An nsAutoPtr<> should be seen as a simple pointer that when you assign a pointer to it, remembers this pointer, but in the case where it already holds a pointer to something when you assign something to it (NULL or another pointer) deletes what-ever it held previously:

// myObj autoinitialised to NULL
nsAutoPtr<myType> myObj;

myObj = new myType(A);
// myObj now holds a pointer to myType(A)

myObj = new myType(B);
// The previous content myType(A) has
// been deleted
and myObj now holds a
// pointer to myType(B)

myObj = NULL;
// myType(B) is now deleted

If you get a pointer back from an argument in a function call this is the way to do it:

// prototype for example func
MyFuncReturningAnObject(myType **);

// When calling the function

// Don’t do like this:
MyFuncReturningAnObject(&myObj); // THIS IS WRONG!!!!

// Do like this:
MyFuncReturningAnObject(getter_Transfers(myObj)); // This is CORRECT!!!!

// Or

// Declare tmp object as normal object
myType *tmpObj;
// Get a pointer to the object you which to keep
// Store the pointer
myObj = tmpObj;

Hence the good thing about nsAutoPtr is that as long as you only have one pointer to each object you are fine and keeping within the intended use of it, but when you need more complex patterns, you better be very careful about ownership and lifetime, or use something else.

Let me illustrate with an example:

nsAutoPtr<myType> myObj1;
nsAutoPtr<myType> myObj2;

myObj1 = new myType(A);
myObj2 = myObj1;
// BE CAREFULL!!! – myObj1 now holds a NULL pointer

or another bad usage:

nsAutoPtr<myType> myObj;
myType* myRawPointer;

myObj = new myType(B);
myRawPointer = myObj;
// So far so good, myObj and myRawPointer both points to the same object

myObj = NULL;
// What myRawPointer points to has now been deleted!

or totally wrong as if you could scale wrongness (don’t try this at home):

nsAutoPtr<myType> myObj1;
nsAutoPtr<myType> myObj2;
myType* myRawPointer;

myObj1 = new myType(C);
myRawPointer = myObj1;
myObj2 = myRawPointer;
// So far so good, all point to myType(C)
// but beware – your code is doomed –
// as in “crash pending”!!!

myObj1 = NULL;
// The object is now gone but even you don’t use
// any of the other variables, the code WILL go
// wrong when myObj2 goes out of scope, as
// the nsAutoPtr<> will try to delete what ever
// myObj2 points to at that time – assinging NULL
// to
myObj2, will only make it crash faster

So this last one was what I attempted, with the two nsAutoPtr’s wrapped into some 3’rd party code, different threads and a couple of function calls – a lesson was learned for me 🙂

Happy coding!