Table of Contents
Tabs/Spaces: Tabs are set at 4, Tabs are converted to spaces
Documentation: Use the doxygen tags as shown in the coding style examples.
Unit Testing the Source Code
In an effort to get the best possibly reliability from the code, the complete code based will gradually be unit tested. The unit tests in the codebase use the QTestLib framework which is part of Qt, so there are no additional dependencies.
You are encouraged to write unit tests for new code you are adding to QGroundControl. To run the exiting test suite, simply run the debug build with –unittest on the command line. You can also run a specific unit test with –unittest:UnitTestName. Existing unit tests can be found in the Unit Test section of the qgroundcontrol.pro file. The current standard is to keep unit test code close to the code that it is testing as opposed to placing it in the qgcunittest directory.
Some useful hints for good C++ programming
This list should give some hints where to put your attention while coding if your new to C++. It is in no way complete and if something is missing feel free to extend the list:
- Try to use references (
'&') as much as possible instead of pointers (
'*'). Especially when a function depends on an object as input.
- Use the C++ casts:
'static_cast<int>(variableName)' instead of
- There is really rarely a reason to pass an object as function argument - use a reference or pointer to it instead.
constas much as possible, this avoids mistakes and helps the compiler to optimize the code.
- When an argument is not changed by a function, define the argument as
void aFunction(const PxClass &rInput)
- When a member function in a class does not change any member variables of its class, define the function as
void aFunction(void) const
- When you return a reference or pointer to internal data that must not be changed from outside, define the return value of the function as
const PxData *aFunction(void)
- Try to avoid pointer arithmetic, this makes it often impossible for the compiler to further optimize your code.
- If an object is only needed localy, create it on the local stack:
PxClass class(args); //NOT Java-like PxClass *class = new PxClass(args);
This has the advantage that the destructor is called automatically when the function exits and no slow memory allocation and deallocation is necessary.
- When defining variables of classes always take care that the compiler wont do unnecessary work. There is a big difference between these 4 possible definitions considering performance (from best to worst):
const PxMatrix3x3 &mat(mat2 * mat3); PxMatrix3x3 mat(mat2 * mat3); PxMatrix3x3 mat = mat2 * mat3; PxMatrix3x3 mat = PxMatrix3x3(mat2 * mat3);
In every case (mat2 * mat3) results in a temporary PxMatrix3x3 object. In the first line a constant reference is initialized to the temporary object, which does not cost anything, its just syntax. But this works only for const references (i.e. you can use this kind of expression for storing temporary results). In the second line the copy constructor of PxMatrix3x3 is called with the temporary result of (mat2 * mat3), in many cases this is optimized so that no copying is necessary (the result of mat2*mat3 is written directly to the local position of mat in the stack). The third and fourth lines show bad definitions: In both cases the standard constructor on the left-hand-side is called, and (third line) the temporary result is copied or (fourth line) the copy constructor is called and then all data is copied. Good compilers can avoid some copying, but especially when non-trivial constructors are used there is always unnecessary copying of data and if the constructors are complex (with database access or similar slow operations) the whole process takes considerable time to run.