Menu
Home
Log in / Register
 
Home arrow Computer Science arrow Learn BlackBerry 10 App Development
< Prev   CONTENTS   Next >

Smart Pointers

I usually prefer to not worry about deleting objects; I would rather delegate the task. Like most difficult problems in programming, you can solve memory management by adding a level of indirection, which in this case is called smart pointers. Smart pointers are actually part of the new C++11 standard, but I am going to concentrate on the QSharedPointer, which is part of the Qt core framework. QSharedPointer is a reference counting smart pointer, meaning that it holds a shared reference to a dynamically allocated object. The pointee will be deleted once the last QSharedPointer pointing to it is destroyed or goes out of scope. Obviously, QSharedPointers must be automatic objects and you cannot allocate them on the heap. (Automatic objects are created on the stack and are destroyed when they get out of scope. To use a QSharedPointer, simply initialize it with a dynamically allocated resource, as shown in Listing 3-19.)

Listing 3-19. QSharedPointer

//don't forget to #include <QSharedPointer>

{ // start of scope

QSharedPointer<MyClass> m_variable(new MyClass); m_variable->method1(); // calls MyClass::method1() m_variable->method2(); // calls MyClass::method2()

} // end of scope. MyClass instance gets deleted here

As you can see, by automatically assigning a dynamically allocated object to a smart pointer, you don't need to worry anymore about deleting the object when it is no longer required. You can also assign a smart pointer to another one or return a smart pointer from a function (the reference count will be automatically handled for you in both cases). In other words, smart pointers make memory management as hassle free as in garbage-collected languages such as Java. Note that initializing a smart pointer, as illustrated previously, is a special case of the C++ “resource acquisition is initialization” (RAII) programming paradigm. RAII is particularly important in order to avoid memory leaks when exceptions happen during class construction. Listing 3-20 illustrates this by first using raw pointers in a class instantiation.

Listing 3-20. Constructor Exception, Raw Pointers

Class MyClass : public QObject{

Q_OBJECT

public:

MyClass(QObject* parent=0) : QObject(parent){ m_var1 = new Type1;

m_var2 = new Type2;

}

virtual ~MyClass() { delete m_var1; delete m_var2;

}

private:

Type* m_var1; Type2* m_var2;

};

The previous code declares two pointer member variables. Let's now imagine that an exception occurs during m_var2's allocation (at this stage, m_var1 has already been allocated). When an exception occurs in a constructor, it is as if the class instance never existed, and the destructor will not be called (in other words, the call to delete m_var1 will not happen and you will face a memory leak). If you

are thinking of handling the exception in the constructor, don't; your code will become unreasonably convoluted and you would still not handle all possible cases. As you might have guessed, smart pointers are the solution. Listing 3-21 gives you a smart pointer version of the previous code.

Listing 3-21. Constructor Exception, Smart Pointers

Class MyClass : public QObject{

Q_OBJECT

public:

MayClass(QObject* parent=0) : QObject(parent), m_var1(new Type), m_var2(new Type2)

{

}

virtual ~MyClass() {

// empty destructor.

}

private:

QSharedPointer<Type> m_var1; QSharedPointer<Type2> m_var2;

};

As illustrated in Listing 3-21, I am using initialization lists to initialize the smart pointers (initialization lists should be preferred when dealing with non-built-in types). So what happens when an exception occurs? As previously, your destructor does not get called but the C++ standard mandates that the destructor of all successfully constructed sub-objects have to be called. (This will effectively release the memory held by m_var1 and avoid any leaks. Note that in the case of “dumb” pointers, the pointer is effectively deleted, but not the pointee; this is why your class needs a destructor in the first place.)

In practice, if you do not handle an exception, it is propagated up the call stack, and eventually, your program will be terminated by the C++ runtime. This could be the sensible thing to do if your

application is in such a “catastrophic state” that it would be pointless to continue running (at the very least, you should create a log trace of the problem). Obviously, smart pointers would not be very helpful in such a situation, and the BlackBerry 10 OS would reclaim the memory anyway. However, if you need to write long-running applications such as headless apps, you need to make sure that your application is resilient; you cannot afford crashing when exceptions occur. Smart pointers will therefore be very useful to avoid memory leaks in exceptional cases by making sure that memory is released.

 
Found a mistake? Please highlight the word and press Shift + Enter  
< Prev   CONTENTS   Next >
 
Subjects
Accounting
Business & Finance
Communication
Computer Science
Economics
Education
Engineering
Environment
Geography
Health
History
Language & Literature
Law
Management
Marketing
Philosophy
Political science
Psychology
Religion
Sociology
Travel