Modern Qt and Smart Pointers
Recently, I set out to breathe some new life into my QtPlex project, which was hacked together many years ago. At the initial time of creation, I didn't have much understanding of C++ and a lot of the code was pretty messy. Part of my cleanup was the desire to utilize smart pointers, of which I had a few options. As it turns out, the decision is much more difficult than it seems on the surface. Let's take a look at some of the most common options and their considerations.
STL Smart Pointers
These are the smart pointers added in C++11, such as std::unique_ptr
and it's cousins. Here are some of the considerations to make when deciding if smart pointers fit into your project:
Pros
- Familiar to most modern C++ developers.
- Clear definitions and ownership.
- Takes advantage of move semantics.
- Compatible with any C++ object.
Cons
- Stack trace readability can decline.
- Most are non-weak, meaning they could point to invalid objects.
- Ugly to use with short-lived pointers, as are common in Qt code.
QtCore Smart Pointers
QtCore provides a number of various smart pointers that have been in the library for many years. While it might seem intuitive to use the same library's implementation, it's not so clear:
Pros
- Blends in well with the existing Qt ecosystem.
- Not as "wordy" in the declarations and usages.
- Provides some niceties to fit in with the parent/child model of Qt.
Cons
- Can only be used with QObject derivatives.
- No move semantics or similar concept.
- Unfamiliar to the average C++ developer.
Raw Pointers
Despite the normal benefits to smart pointers, it's important to question if smart pointers even belong in a modern Qt application.
There are many who would argue, convincingly, that the answer is no. Qt is designed with an hierarchical management system that is very stable. Parents are responsible for cleaning up their children, and each child belongs to only one parent. This tree-based structure also helps to clearly define ownership. Pointers are often short-lived references that are passed into their parent objects and discarded. Rarely do we need to juggle and retain multiple pointers to the same object, thus severely mitigating the risks of dangling pointers or memory leaks.
Conclusion
Ultimately, I decided to opt for STL smart pointers. I think the move semantics, clear ownership and familiarity to most modern developers are benefits that can't be understated. Additionally, STL smart pointers help to enforce, and even compliment, Qt's hierarchical management system by ensuring parent objects retain explicit ownership of their children.
That being said, I don't feel as if there is truly a "correct" decision in this case, and the context of your application should really help shape this choice. For smaller, simple applications you likely can get away with raw pointers. Open-source applications, like mine, might benefit from the familiarity of STL's smart pointers. Large, enterprise applications would likely want to stick with the QtCore library which would be familiar to the Qt gurus.