coding_style
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
coding_style [2016/03/02 12:32] – jmgr | coding_style [2023/04/25 16:52] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== | + | ====== |
- | ===== General ====== | + | ===== Spaces vs Tabs ===== |
- | + | Qt Creator uses spaces for indentation. Since we will probably be using Qt and since Qt Creator is the default IDE when writing code using Qt, **spaces** should be used for indentation. | |
- | ==== Tips & tricks ==== | + | |
- | + | ||
- | === Always initialise primitive variables (other types do not require this) === | + | |
+ | ===== Braces ===== | ||
+ | Opening and closing braces should be on a new line, in most cases: classes, functions, namespaces, arrays, etc. The only exception would be initialization. | ||
<code cpp> | <code cpp> | ||
- | // Bad | + | namespace MyNamespace |
- | int myVariable; | + | |
- | std::string myString; | + | |
- | + | ||
- | // Good | + | |
- | int myVariable{}; | + | |
- | std::string myString; | + | |
- | </ | + | |
- | + | ||
- | === Always set parameters as const reference if they are non-primitives === | + | |
- | + | ||
- | <code cpp> | + | |
- | // Bad | + | |
- | void myFunction(int firstParameter, | + | |
{ | { | ||
- | //... | + | void MyFunction() |
- | } | + | { |
- | + | while(true) | |
- | // Good | + | { |
- | void myFunction(int firstParameter, | + | int value{42}; |
- | { | + | } |
- | //... | + | } |
} | } | ||
</ | </ | ||
- | === Do not use "using namespace" | + | ===== Naming ===== |
- | + | ||
- | <code cpp> | + | |
- | // Bad | + | |
- | using namespace std; | + | |
- | + | ||
- | void myFunction() | + | |
- | { | + | |
- | string myString; | + | |
- | //... | + | |
- | } | + | |
- | + | ||
- | // Good | + | |
- | void myFunction() | + | |
- | { | + | |
- | using namespace std; | + | |
- | + | ||
- | string myString; | + | |
- | //... | + | |
- | } | + | |
- | + | ||
- | // Better | + | |
- | void myFunction() | + | |
- | { | + | |
- | std::string myString; | + | |
- | //... | + | |
- | } | + | |
- | </ | + | |
- | Note that you can use namespace aliases to simplify a complex namespace hierarchy: | + | ^ Item ^ Example ^ Comment ^ |
- | + | | type (class/ | |
- | <code cpp> | + | | variable | someExample | | |
- | namespace myNamespace = some:: | + | | member variable | m_someExample | | |
- | </ | + | | global variables | gSomeExample | should be avoided | |
- | + | | function | someExample() | function names should begin with a verb: computeMap(), | |
- | === Use references instead of pointers if possible => easier to use (but note that Qt uses a lot of pointers for historical reasons) === | + | | member function | someExample() | | |
+ | | getter function | name() | not getName(), | ||
+ | | setter function | setName() | | | ||
+ | | namespace | SomeExample | | | ||
+ | | template parameter | SomeExample | | | ||
+ | **Never use abbreviations in names, having long names is not an issue: all IDEs have an auto-completion feature.** | ||
<code cpp> | <code cpp> | ||
// Bad | // Bad | ||
- | void myFunction(MyObject *object) | + | void getNbApples() |
{ | { | ||
- | object-> | + | int avgFuncSizePerAlloc = 42; |
- | //... | + | //... |
} | } | ||
// Good | // Good | ||
- | void myFunction(MyObject &object) | + | void getAppleCount() |
{ | { | ||
- | object.function(); | + | int averageFunctionSizePerAllocation = 42; |
- | //... | + | //... |
} | } | ||
</ | </ | ||
- | === Use smart pointers | + | **Prefer using meaningful names instead of "one letter" |
<code cpp> | <code cpp> | ||
// Bad | // Bad | ||
- | MyObject *object | + | for(int i = 0; i < ducks.size(); ++i) |
- | + | ||
- | delete object; | + | |
- | + | ||
- | // Good | + | |
- | # | + | |
- | + | ||
- | std:: | + | |
- | + | ||
- | // Good | + | |
- | #include < | + | |
- | + | ||
- | // parentObject is a pointer to a QObject | + | |
- | + | ||
- | MyObject *object = new MyObject(parentObject); | + | |
- | </ | + | |
- | + | ||
- | === If you have to write a function that returns multiple values, prefer returning a std::tuple instead of using reference parameters (if possible) === | + | |
- | + | ||
- | <code cpp> | + | |
- | // Bad | + | |
- | void myFunction(int & | + | |
{ | { | ||
- | outFirstVariable = 42; | + | //... |
- | outSecondVariable = " | + | |
} | } | ||
// Good | // Good | ||
- | #include < | + | for(int duckIndex = 0; duckIndex < ducks.size(); ++duckIndex) |
- | + | ||
- | std:: | + | |
{ | { | ||
- | return std:: | + | //... |
} | } | ||
- | |||
- | // auto result = myFunction(); | ||
- | // Use std:: | ||
</ | </ | ||
- | === When using events, prefer using lambdas (nameless functions) instead of static functions === | + | **Variables representing GUI elements should be suffixed by their type** |
<code cpp> | <code cpp> | ||
- | #include < | ||
- | |||
- | QPushButton *button = new QPushButton(parent); | ||
- | |||
// Bad | // Bad | ||
- | void MyObject:: | + | QPushButton *exitApplication; |
- | { | + | QLabel *duckCount; |
- | //... | + | |
- | } | + | |
- | + | ||
- | connect(button, | + | |
// Good | // Good | ||
- | connect(button, | + | QPushButton |
- | { | + | QLabel *duckCountLabel; |
- | //... | + | |
- | }); | + | |
</ | </ | ||
- | |||
- | === Never forward-declare variables === | ||
- | |||
- | <code cpp> | ||
- | // Bad | ||
- | int i; | ||
- | int j; | ||
- | |||
- | for(; i < 10; ++i) | ||
- | { | ||
- | for(; j < 10; ++j) | ||
- | { | ||
- | //... | ||
- | } | ||
- | } | ||
- | |||
- | // Good | ||
- | for(int i{}; i < 10; ++i) | ||
- | { | ||
- | for(int j{}; j < 10; ++j) | ||
- | { | ||
- | //... | ||
- | } | ||
- | } | ||
- | </ | ||
- | |||
- | === Write small functions instead of huge ones === | ||
- | === Never call virtual functions from a constructor === | ||
- | Reference: [[https:// | ||
- | ===== Qt specific ===== | ||
- | |||
- | ==== Containers ==== | ||
- | |||
- | ^ C++ Standard Library ^ Qt ^ | ||
- | | [[http:// | ||
- | | [[http:// | ||
- | | [[http:// | ||
- | | [[http:// | ||
- | | [[http:// | ||
- | | [[http:// | ||
- | | [[http:// | ||
- | |||
- | *If in doubt, use [[https:// | ||
- | |||
- | **/!\ [[http:// | ||
- | |||
- | Prefer using [[https:// | ||
- | ==== Inheritance ==== | ||
- | |||
- | QObject-based: | ||
- | * automatic memory management (no smart pointer required) | ||
- | * constructor takes a parent QObject, defaulted to nullptr | ||
- | * Q_OBJECT macro at the beginning of the class | ||
- | |||
- | <file cpp myobject.hpp> | ||
- | #pragma once | ||
- | |||
- | #include < | ||
- | |||
- | class MyObject: public QObject | ||
- | { | ||
- | Q_OBJECT | ||
- | | ||
- | public: | ||
- | MyObject(QObject *parent = nullptr); | ||
- | virtual ~MyObject(); | ||
- | } | ||
- | </ | ||
- | |||
- | <file cpp myobject.cpp> | ||
- | #include " | ||
- | |||
- | MyObject:: | ||
- | QObject(parent) | ||
- | { | ||
- | } | ||
- | |||
- | MyObject:: | ||
- | { | ||
- | } | ||
- | </ | ||
- | |||
- | QWidget-based: | ||
- | * automatic memory management (no smart pointer required) | ||
- | * constructor takes a parent QWidget, defaulted to nullptr | ||
- | * Q_OBJECT macro at the beginning of the class | ||
- | |||
- | <file cpp mywidget.hpp> | ||
- | #pragma once | ||
- | |||
- | #include < | ||
- | |||
- | class MyWidget: public QWidget | ||
- | { | ||
- | Q_OBJECT | ||
- | | ||
- | public: | ||
- | MyClass(QWidget *parent = nullptr); | ||
- | virtual ~MyClass(); | ||
- | } | ||
- | </ | ||
- | |||
- | <file cpp mywidget.cpp> | ||
- | #include " | ||
- | |||
- | MyWidget:: | ||
- | QWidget(parent) | ||
- | { | ||
- | } | ||
- | |||
- | MyWidget:: | ||
- | { | ||
- | } | ||
- | </ | ||
- | |||
- | Other classes: | ||
- | * memory management through smart pointers | ||
- | |||
- | ==== Exceptions ==== | ||
- | |||
- | [[https:// | ||
- | |||
- | If you are writing non-Qt code then you really should use exceptions and more importantly, | ||
- | ====== Style ====== | ||
- | |||
===== Code files ===== | ===== Code files ===== | ||
==== Code separation ==== | ==== Code separation ==== | ||
- | Generally speaking, each class/ | + | Generally speaking, each class/ |
==== Naming ==== | ==== Naming ==== | ||
Line 311: | Line 110: | ||
This feature in implemented in all known compilers and is both easier to use and foolproof. It has not been accepted into the C++ standard because of some particular cases, like having source files on multiple " | This feature in implemented in all known compilers and is both easier to use and foolproof. It has not been accepted into the C++ standard because of some particular cases, like having source files on multiple " | ||
- | ====== Examples ====== | ||
- | <code cpp> | ||
- | #include < | ||
- | #include < | ||
- | |||
- | // An entity semantic class | ||
- | class MyExampleClass final | ||
- | { | ||
- | public: | ||
- | // This constructor is explicit to prevent something like this: MyExampleClass test = "some text"; | ||
- | explicit MyExampleClass(const std::string & | ||
- | m_myVar{52}, | ||
- | m_myString{myString} | ||
- | { | ||
- | } | ||
- | |||
- | // Entity semantic: always forbid copy & assignment | ||
- | MyExampleClass(const MyExampleClass &) = delete; | ||
- | MyExampleClass & | ||
- | |||
- | private: | ||
- | // Variables are always at the end, because they represent an implementation detail | ||
- | int m_myVar{42}; | ||
- | std::string m_myString{" | ||
- | }; | ||
- | |||
- | // A value semantic class | ||
- | class MyVector final // Always final: a value semantic class should *never* be inherited from | ||
- | { | ||
- | public: | ||
- | // We want to use the default implementation (wich is faster than anything we can do) | ||
- | MyVector() = default; | ||
- | |||
- | MyVector(const MyVector & | ||
- | m_x(other.m_x), | ||
- | m_y(other.m_y) | ||
- | { | ||
- | } | ||
- | |||
- | MyVector & | ||
- | { | ||
- | std:: | ||
- | std:: | ||
- | |||
- | return *this; | ||
- | } | ||
- | |||
- | private: | ||
- | // m_x and m_y are initialized with the default value for the type int: 0 | ||
- | // unless the initializer list in a constructor decides otherwise | ||
- | int m_x{}; | ||
- | int m_y{}; | ||
- | }; | ||
- | |||
- | void test() | ||
- | { | ||
- | // I use scopes " | ||
- | { | ||
- | // Allocation on the stack (fast) | ||
- | MyExampleClass myExampleClass{" | ||
- | // myExampleClass is destroyed here | ||
- | } | ||
- | { | ||
- | // Allocation on the heap (slower, allows polymorphism) | ||
- | std:: | ||
- | // Or (with auto) | ||
- | auto myExampleClass{std:: | ||
- | // myExampleClass is destroyed here (thanks to the smart pointer) | ||
- | } | ||
- | } | ||
- | </ |
coding_style.1456921955.txt.gz · Last modified: 2023/04/25 16:52 (external edit)