1,072
edits
(Add section for lambda expressions) |
|||
(60 intermediate revisions by 7 users not shown) | |||
Line 7: | Line 7: | ||
== Formatting == | == Formatting == | ||
=== Line Length === | |||
There is no fixed line length. In general, strive for clarity and readability and use your own judgement. | |||
Everyone has access to monitors with more than 80 columns, but even so, exceptionally long lines can be hard to read. However, keeping code together on a line that is logically one unit does improve readability. | |||
=== Indentation === | === Indentation === | ||
Use only spaces, | * Use only spaces, with 2 spaces per indent. | ||
* Tabs are prohibited. | |||
==== Functions, class, struct, enum ==== | |||
The curly braces defining the beginning and end of the block should appear on their own line. | |||
The braces should not be indented, i.e., they align at the same indentation level as the keyword such as {{codeline|class}}. | |||
the | |||
The body of the block is indented. | |||
Note that class access specifiers {{codeline|public}}, {{codeline|protected}}, {{codeline|private}} are not indented. | |||
are | |||
Example: | |||
<syntaxhighlight lang="cpp"> | |||
class MatrixType | |||
{ | { | ||
public: | |||
enum matrix_type | |||
{ | |||
Unknown = 0, | |||
Full, | |||
Rectangular | |||
}; | |||
} | |||
</syntaxhighlight> | |||
==== Control structures (if, while, ...) ==== | |||
When indenting, indent the statement after control structures (like {{codeline|if}}, {{codeline|while}}, etc.). | |||
If there is a compound statement, indent ''both'' the curly braces and the body of the statement (so that the body gets indented by ''two'' indents). | |||
Example: | |||
<syntaxhighlight lang="cpp"> | |||
if (have_args) | |||
{ | |||
idx.push_back (first_args); | |||
have_args = false; | |||
} | |||
else | |||
idx.push_back (make_value_list (args, arg_nm, tmp)); | |||
</syntaxhighlight> | |||
If you have nested {{codeline|if}} statements, use extra braces for extra clarification. | |||
==== Switch statements ==== | |||
Indent ''both'' the curly braces and the body of the switch statement (so that the body gets indented by ''two'' indents). | |||
However, the {{codeline|case}} statement is not doubly indented and instead aligns with the first brace. | |||
<syntaxhighlight lang="cpp"> | |||
switch (info) | |||
{ | { | ||
case -1: | |||
{ | { | ||
cout << "function failed\n"; | |||
return false; | |||
}; | } | ||
case 0: | |||
return true; | |||
} | } | ||
} | </syntaxhighlight> | ||
</ | |||
==== #ifdef directives ==== | |||
Indent code that follows a conditional processor directive such as {{codeline|#ifdef}} or {{codeline|#else}}. | |||
Example | |||
<syntaxhighlight lang="cpp"> | |||
#if defined (HAVE_CONFIG_H) | |||
# include "config.h" | |||
#endif | |||
</syntaxhighlight> | |||
The '#' character may also be placed with the directive rather than remaining in column 1 if this looks better. | |||
==== Split long expressions ==== | |||
Split long expressions in such a way that a continuation line starts | |||
with an operator rather than identifier. If the split occurs inside | |||
braces, continuation should be aligned with the first char after the | |||
innermost braces enclosing the split. Example: | |||
<syntaxhighlight lang="cpp"> | |||
SVD::type type = ((nargout == 0 || nargout == 1) | |||
? SVD::sigma_only | |||
: (nargin == 2) ? SVD::economy : SVD::std); | |||
</syntaxhighlight> | |||
==== Optional braces ==== | |||
Consider putting extra braces around a multi-line expression to make it | |||
more readable, even if they are not necessary. Also, do not hesitate to | |||
put extra braces anywhere if it improves clarity. | |||
=== Pointer and Reference appearance === | |||
Declarations of pointers have the '*' character cuddled with the ''name'' of the variable. | |||
<syntaxhighlight lang="cpp"> | |||
unsigned int *pointer_variable; | |||
</syntaxhighlight> | |||
However, references have the '&' character cuddled with the ''type'' of the variable. | |||
<syntaxhighlight lang="cpp"> | |||
unsigned int& reference_variable; | |||
</syntaxhighlight> | |||
=== Miscellaneous === | |||
The negation operator is written with a space between the operator | |||
and its target, e.g., {{codeline|! A}}. | |||
=== Function headers === | |||
In general, in non-header files, format function headers like this: | |||
<syntaxhighlight lang="cpp"> | |||
static bool | |||
matches_patterns (const string_vector& patterns, int pat_idx, | |||
int num_pat, const std::string& name) | |||
</syntaxhighlight> | |||
The return type of the function and any modifiers are specified on the first | |||
line. The function name on the second line should start in column 1, and | |||
multi-line argument lists should be aligned on the first character after the open | |||
parenthesis. Put a space before the left open parenthesis and after | |||
commas, for both function definitions and function calls. | |||
For header files, or in class definitions, it may look better not to split the return type from the rest of the function header. Use your own judgement. | |||
=== Class declarations === | |||
The access specifier ({{codeline|public}}, {{codeline|protected}}, {{codeline|private}}) should always be stated rather than relying on the C++ language defaults for a particular object (for example, "{{codeline|class}}" = "{{codeline|private}}"). | |||
Within a class, the different access blocks should appear in the order 1) {{codeline|public}}, 2) {{codeline|protected}}, 3) {{codeline|private}}. | |||
Within an access block, member functions (methods) should be specified before member variables. If there are both member functions and member variables use | |||
//-------- | |||
between the sections to visually separate the two categories. | |||
=== Namespace === | |||
All code should be in the {{codeline|octave}} namespace or in a namespace below it. | |||
Namespaces should start and stop using the special macros {{codeline|OCTAVE_BEGIN_NAMESPACE(XXX)}} and {{codeline|OCTAVE_END_NAMESPACE(XXX)}}. There is no indentation of code that is placed into namespaces using these macros. | |||
Example | |||
{{Code|Use of namespace macros|<syntaxhighlight lang="cpp"> | |||
OCTAVE_BEGIN_NAMESPACE(octave) | |||
OCTAVE_BEGIN_NAMESPACE(math) | |||
template <typename T> | |||
void | |||
umfpack_report_control (const double *Control); | |||
OCTAVE_END_NAMESPACE(math) | |||
OCTAVE_END_NAMESPACE(octave) | |||
</syntaxhighlight>}} | |||
If bare namespace directives must be used, as occasionally is required in Qt code, then the code within the namespace should be indented. | |||
{{Code|namespace | {{Code|bare namespace usage|<syntaxhighlight lang="cpp"> | ||
// Note indentation and that functions are not defined | // Note indentation and that functions are not defined as "octave::math::foo:foo" | ||
namespace octave | namespace octave | ||
{ | { | ||
Line 62: | Line 202: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight>}} | ||
==== Other Guidelines ==== | |||
* Do not use {{codeline|using XXX;}} directives | |||
* Do not declare anything on the {{codeline|std::}} namespace | |||
== Naming == | |||
Use lowercase names if possible. Uppercase is acceptable for variable names consisting of 1-2 letters. Do not use mixed case (a.k.a. CamelCase) names. | |||
=== Member Variables === | |||
Member variables should use the prefix "m_" whenever possible. | |||
=== Class Variables === | |||
Class variables should use the prefix "s_" (for "static") whenever possible. | |||
=== Filenames === | |||
As with m-files, the file name of a C++ source file containing a class should match the name of the class defined within the file. For example, "password.h" defines the class "password" rather than "passwd.h" which is a common abbreviation for "password". | |||
== Header Files == | == Header Files == | ||
Line 68: | Line 228: | ||
=== Order of Includes === | === Order of Includes === | ||
In source files (not headers files), use the following order with an empty line between each section: | |||
# config.h | # config.h | ||
# The C++ wrappers for C headers (cstdlib, cassert, etc.) | # The C++ wrappers for C headers (cstdlib, cassert, etc.) | ||
# C++ standard library headers (iostream, list, map, etc.) | # C++ standard library headers (iostream, list, map, etc.) | ||
# Other library header files (glpk.h, curl.h, etc., should be protected by {{codeline|#if defined (HAVE_FOO_H)}} since they may be missing on the build system) | # Other library header files (glpk.h, curl.h, etc., should be protected by {{codeline|#if defined (HAVE_FOO_H)}} since they may be missing on the build system) | ||
# Octave's liboctave headers | # Octave's liboctave headers | ||
# Octave's libinterp headers | # Octave's libinterp headers | ||
# Octave's libgui headers | |||
Other POSIX headers (sys/types.h, unistd.h, etc., should not be included directly into Octave sources. For portability, use a wrapper function. Anything you need is probably already available as a wrapper around a function or header provided by gnulib. See the files in liboctave/wrappers. This is necessary because although gnulib is great for portability, it does not generally work well with C++. | |||
Similarly, Windows headers should not be included directly into Octave sources. Wrappers that provide the needed functionality in an OS-independent way should be used instead. This is almost always possible and there are many examples in the Octave sources. | |||
Each grouping of header files should be alphabetized unless there is some | Each grouping of header files should be alphabetized unless there is some | ||
Line 82: | Line 246: | ||
{{Path|oct-parse.in.yy}} and there is a comment in the file for that one. | {{Path|oct-parse.in.yy}} and there is a comment in the file for that one. | ||
== | There is a strict ordering of header files/libraries that must be followed. There are '''no exceptions''' to these rules: | ||
* The functions in liboctave/wrappers may only use headers and symbols from gnulib, standard libraries, or OS-dependent libraries. They '''must not''' use any headers or symbols from other parts of liboctave, libinterp, or libgui. | |||
* liboctave '''must not''' use any headers or symbols from libinterp or libgui. It must be fully functional without the interpreter or GUI. | |||
* libinterp '''must not''' use any headers or symbols from libgui. It must be fully functional without the GUI. | |||
As much as possible, header files should be independent of other header files. | |||
Header files '''must not''' include config.h. Instead, they should begin by including octave-config.h. | |||
Header files should not use any "#if defined (HAVE_FEATURE)" conditionals. This is not quite true yet, but we are almost there. '''No new conditionals may be added.''' | |||
== C++ features == | |||
=== references === | |||
Use references when passing variables that will be changed by a subroutine rather than the C-style method of passing pointers. | |||
{| class="wikitable" | |||
! style="color:green;" | good | |||
! style="color:darkred;" | bad | |||
|- | |||
| <syntaxhighlight lang="c++"> | |||
void foo (int& a_ref) | |||
{ | |||
// foo changes content of `a_ref` | |||
a_ref = a_ref + 1; | |||
} | |||
void bar () | |||
{ | |||
int a = 42; | |||
foo (a); | |||
} | |||
</syntaxhighlight> | |||
| <syntaxhighlight lang="c++"> | |||
void foo (int *a_ptr) | |||
{ | |||
// foo changes content of `a_ptr` | |||
*a_ptr = *aptr + 1; | |||
} | |||
void bar () | |||
{ | |||
int a = 42; | |||
foo (&a); | |||
} | |||
</syntaxhighlight> | |||
|} | |||
When passing variables that are large, but will not be changed in a subroutine (read-only), use {{codeline|const}} references. This helps avoid overflowing the finite stack capacity of a program while still ensuring that read-only access is enforced. | |||
{| class="wikitable" | |||
! style="color:green;" | good | |||
! style="color:darkred;" | bad | |||
|- | |||
| <syntaxhighlight lang="c++"> | |||
void foo (const std::string& str_ref) | |||
{ | |||
// foo does not change content of `str_ref` | |||
} | |||
void bar () | |||
{ | |||
std::string str ("This is a large variable, however as a reference it will take up just 8 bytes on the stack when passed to the subroutine foo()"); | |||
foo (str); | |||
} | |||
</syntaxhighlight> | |||
| <syntaxhighlight lang="c++"> | |||
void foo (std::string str_copy) | |||
{ | |||
// foo does not change content of `str_copy` | |||
} | |||
void bar () | |||
{ | |||
std::string str ("This is a large variable that will be copied on to the stack and passed as a temporary variable to the subroutine foo()"); | |||
foo (str); | |||
} | |||
</syntaxhighlight> | |||
|} | |||
=== new/delete === | |||
Pointers that will be allocated memory with {{codeline|new}} should be initialized with the C++ literal {{codeline|nullptr}}, not the numerical value 0 or the macro {{codeline|NULL}}. | |||
The {{codeline|delete}} keyword accepts {{codeline|nullptr}} and programmers should not put an {{codeline|if (ptr)}} guard around {{codeline|delete}}. | |||
{| class="wikitable" | |||
! style="color:green;" | good | |||
! style="color:darkred;" | bad | |||
|- | |||
| <syntaxhighlight lang="c++"> | |||
delete ptr; | |||
</syntaxhighlight> | |||
| <syntaxhighlight lang="c++"> | |||
if (ptr) | |||
delete ptr; | |||
</syntaxhighlight> | |||
|} | |||
=== lambda expressions === | |||
When capturing variables from the surrounding function, explicitly list the variables being captured rather than relying on a default capture by value (`[=]`) or by reference (`[&]`). This more clearly captures the programmer's intent and makes the code more understandable. | |||
=== | === std::string === | ||
When an empty string is required, use <code>""</code>, rather than creating an empty | |||
use | string object with <code>std::string ()</code>. | ||
=== auto === | |||
Use of {{codeline|auto}} is allowed only where it helps readability | Use of {{codeline|auto}} is allowed only where it helps readability | ||
Line 98: | Line 365: | ||
* Beware of copy when using {{codeline|auto}} in for loops. Pass by reference and use {{codeline|const}} unless you're dealing with simple types such as {{codeline|int}}. See [http://lists.gnu.org/archive/html/octave-maintainers/2016-06/msg00144.html 'auto' uses and for-range loops] on the maintainers mailing list for more details. | * Beware of copy when using {{codeline|auto}} in for loops. Pass by reference and use {{codeline|const}} unless you're dealing with simple types such as {{codeline|int}}. See [http://lists.gnu.org/archive/html/octave-maintainers/2016-06/msg00144.html 'auto' uses and for-range loops] on the maintainers mailing list for more details. | ||
=== C++14 === | === C++ style casting === | ||
Always use one of the four C++ long style casting forms ({{codeline|static_cast}}, {{codeline|dynamic_cast}}, {{codeline|reinterpret_cast}}, {{codeline|const_cast}}) rather than C-style forms (type cast {{codeline|(new_type) variable}} or the function form {{codeline|new_type (variable)}}). | |||
=== C++11 features === | |||
A C++11 compatible compiler is required for [[Building | building Octave]]. Please make use of all C++11 features. | |||
=== C++14, C++17, C++20 features === | |||
Try to avoid C++14, C++17, or C++20 features. Octave is widely used in very old systems and we want them to be able to use up to date versions of Octave. Building a recent compiler in such systems is not a trivial task so the limitation must happen | |||
want them to be able to use up to date versions of Octave. Building a recent | |||
compiler in such systems is not a trivial task so the limitation must happen | |||
in Octave. | in Octave. | ||
If the implementation using a C++14, C++17, or C++20 feature is very beneficial, make it optional via <code>configure</code> feature detection or also implement an alternative code in the absence of said feature. In any case, please get in contact with the Octave maintainers on [https://octave.discourse.group/c/maintainers/7 Discourse]. | |||
alternative code in the absence of said feature. In | |||
<syntaxhighlight lang="cpp"> | |||
#if defined (HAVE_THIS_C14_FEATURE) | |||
// code that really needs it | |||
#else | |||
// alternative code in its absence | |||
#endif | |||
</syntaxhighlight> | |||
== Doxygen == | |||
Doxygen documentation can be a great help when developing octave however the current state has a lot of room for improvement. For more information about Doxygen in Octave look at [[Doxygen]]. | |||
=== Doxygen Style Guide === | |||
Doxygen allows for a variety of commenting styles. In order to maintain uniformity across the entire project the following rules should be applied: | |||
* For Doxygen comments use only {{codeline|//!}} and NOT {{codeline|/*! ... */}}, regardless of the size of the block comment | |||
* Use {{codeline|@}} for any [https://www.stack.nl/~dimitri/doxygen/manual/commands.html Doxygen Special Commands] | |||
* Use as little formatting as possible. Restrict to [https://www.stack.nl/~dimitri/doxygen/manual/markdown.html Markdown] and avoid HTML-markup. | |||
* Do NOT use the {{codeline|@brief}} command, the first sentence will automatically be used as the summary description. | |||
* The first sentence should describe briefly what the function does and end with a period. | |||
* Leave a blank line between the Doxygen comment and function definition. | |||
An example of properly used Doxygen would look like: | |||
<syntaxhighlight lang="cpp"> | |||
//! Does something interesting with its arguments. | |||
//! | |||
//! Long comment with **bold** special commands. | |||
//! | |||
//! @param some_param Really should figure out what to do. | |||
//! @param another_param Does something cool with @p some_param. | |||
//! | |||
//! And some example using syntax highlighting: | |||
//! | |||
//! @code{.cc} | |||
//! double v = 1.0; | |||
//! int n = 2; | |||
//! some_function (v, n); | |||
//! @endcode | |||
void | |||
some_function (double some_param, int another_param) | |||
{ | |||
// ... | |||
} | |||
</syntaxhighlight> | |||
== Comments == | |||
=== FIXME notes === | |||
The preferred comment mark for places that may need further attention is | |||
with {{codeline|FIXME:}} comments. | |||
[[Category:Development]] | |||
edits