-
Notifications
You must be signed in to change notification settings - Fork 0
Code readability guidelines
It is easier to understand code that has a good readability. The following guidelines should help to produce easily readable code. Even if it can't make complex algorithms simpler it ensures that you can at least follow the used set of instructions.
If there are just a few lines, it is more likely to understand the function. Move subtasks of an algorithm to separate functions and give them a meaningful name. The compiler will most likely inline it anyways so that it won't result in a performance hit. This way a function which might contain hundreds of lines (when everything is written in place) might look like this:
The intention of this is basically the same as in the previous subsection. Blank lines should be used to mark the end of a set of instructions which accomplish a subtasks
void InsertIntoDataFile(char* fileName)
{
auto file = OpenDataFile(fileName);
auto position = FindPositionToWrite(file);
WriteToFile(file, position);
CloseFile(file);
}When declaring an instance of a template class the line of code can get messy quiet fast. In this case it is better to use a typedef or the using keyword to define a short descriptive name.
It is much easier to understand a class that only consists of a few functions and members. It is tempting to code a class which offers a lot of useful features, but most of the time those are not necessary to fulfill the basic purpose. So stick to a limited set of function that are needed by the class to do its core job. Move additional functionality to a separate class or function collection which has the purpose to offer this extra features.
Example: A class for a shader program should basically enable the user to compile a program, set its internal variable (uniforms etc.) and free all resources if the program is no longer needed. So you need some kind of initialization function, some getters and setters for its variables and a deinitialization function. When setting a uniform variable one usually needs to know the program internal handle of that uniform. Since the handle is set during the shader programs compilation there is usually just one way to get this handle: Asking the program for it. So the program class should provide such a feature. To query a handle one needs the name of the variable which is used in the shader program. Now there are two ways to get these names: You have the shader code and can look it up, or you can query all variables and create a list of all available uniform names. If one does not know the shader code a function to get all variables at the program class would be helpful, but this additional functionality is more optional than necessary. It is a good candidate to be moved to an extra class or function collection.
Always use range based for loops if there is no need to know the element number/counter.
for (const auto& element : elements)
{
// ... do some stuff ...
}Structured bindings are a c++17 feature which make it possible to extract multiple values from a class or array and assign them to different variables within a single line. Additionally it is not even necessary to declare those variables. Beside the obvious usecase of multiple return values it can be used in a nice fashion to simplify a range based for loop over a map (code snipped at the end of the section). Other use cases can be found here. Be careful though with using it for multiple return values. The detour over a std::tuple might cost some performance (read here).
From linked stack overflow site:
int main()
{
std::map<int, int> m = {{ 0, 1 }, { 2, 3 }};
for(auto &[key, value] : m)
std::cout << key << ": " << value << std::endl;
}