Projects/Edu/KStars/C++ Best Practices for KStars
This page describes how to use some C++ features while developing KStars.
Smart Pointers
std::unique_ptr
std::unique_ptr hold an object in a scope (local or class variable) and when the unique pointer is destroyed, the owned object is also destroyed. This smart pointer has a release() function to release the ownership and get the pointer to the held object. This smart pointer is the most lightweight because it does not have any internal reference counting. On the other side, it cannot be copied thus you cannot return a std::unique_ptr from a function and containers (vector, map) cannot hold these pointers.
This approach is good for:
- Temporary allocated variables in functions which are destroyed when an error path is executed before leaving the function, we can write code without worrying the forgotten undeleted object what would be a memory leak. The allocated object can be returned by release() function when leaving the function if everything is okay. Just imagine a 100 lines long function with many ifs and while cycle, it is easy to forget to delete a temporary allocated object:
MyObj* MyFunction() { std::unique_ptr<MyObj> LocalObj(new MyObj); if (something_is_wrong1) { return nullptr; } if (something_is_wrong2) { return nullptr; } return LocalObj.release(); }
- Declare a class variable which is not necessarily allocated, but you want to delete it after the class itself destroyed automatically. This design pattern spares the initialization of the class variable to nullptr because a unique pointer is set to nullptr by default. On the other hand, the delete functions in the destructor are not needed and a source of the possible memory leaks is eliminated by design, you cannot forget it:
struct MyClass { ~MyClass { } // We don't have to delete MyObj, it is destroyed automatically by ObjVar. void Allocate() { ObjVar.reset(new MyObj); // Allocate a MyObj instance and set to ObjVar } void Release() { ObjVar.reset(); // We can delete MyObj any time by this call } void DoSomething() { // The get() function gives access to the raw pointer of the owned object (MyObJ*) if (ObjVar.get() == nullptr) return; // We can call MyObj::DoThings() transparently with -> like the syntax of a raw pointer (MyObj*) ObjVar->DoThings(); } std::unique_ptr<MyObj> ObjVar; };