Projects/Edu/KStars/C++ Best Practices for KStars: Difference between revisions

From KDE TechBase
< Projects‎ | Edu‎ | KStars
No edit summary
Line 54: Line 54:
== Initialization of class variables ==
== Initialization of class variables ==


A class can have multiple constructors with different parameters. The class variables had to be initialized by hand in each constructor in the past, but C++11 eliminated this error-prone situation by allowing the initial value declaration in the header file. In this way, the initial values are declared in one place and code editors can also view it in their context-sensitive help. For example, CLion shows the type and the initial value if you go over a class variable with the mouse pointer while holding the Ctrl button. It is much easier than digging around the source code if you are interested in the initial value during coding.
A class can have multiple constructors with different parameters. The class variables had to be initialized by hand in each constructor in the past, but C++11 eliminated this error-prone situation by allowing the initial value declaration in the header file. In this way, the initial values are declared in one place and code editors can also view it in their context-sensitive help. For example, CLion shows the type and the initial value if you go over a class variable with the mouse pointer while holding the Ctrl button. It is much easier than digging around the source code if you are interested in an initial value during coding.


The initial value can be written in braces { 0 } or with assignment operator = 0, these styles are equivalent, but the braces were chosen for the common pattern in KStars.
The initial value can be written in braces (int myVar = { 0 };) or with assignment operator (int myVar = 0;), these styles are equivalent, but the braces were chosen for the common pattern in KStars.


Example myclass.h:
Example myclass.h:

Revision as of 14:37, 28 July 2017

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;
  };

Initialization of class variables

A class can have multiple constructors with different parameters. The class variables had to be initialized by hand in each constructor in the past, but C++11 eliminated this error-prone situation by allowing the initial value declaration in the header file. In this way, the initial values are declared in one place and code editors can also view it in their context-sensitive help. For example, CLion shows the type and the initial value if you go over a class variable with the mouse pointer while holding the Ctrl button. It is much easier than digging around the source code if you are interested in an initial value during coding.

The initial value can be written in braces (int myVar = { 0 };) or with assignment operator (int myVar = 0;), these styles are equivalent, but the braces were chosen for the common pattern in KStars.

Example myclass.h:

  struct MyClass
  {
    int Counter { 1 };
    float Counter2 { 0 };
  };