Editing C++ style guide

Jump to navigation Jump to search
Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.

Latest revision Your text
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, with 2 spaces per indent.
Use only spaces, and indent 2 spaces at a time.
* 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 body of the block is indented.
 
Note that class access specifiers {{codeline|public}}, {{codeline|protected}}, {{codeline|private}} are not indented.
 
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.).
We use spaces for indentation. Absolutely do not use tabs in your code.
You should probably set your editor to emit spaces when you hit the tab key.


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).
When indenting, indent the statement after control
 
structures (like {{codeline|if}}, {{codeline|while}}, etc.).  If there
Example:
is a compound statement, indent ''both'' the curly braces and the
body of the statement (so that the body gets indented by ''two''
indents). This format is known as "GNU style" and is an option for
some code formatting tools.  Example indenting:


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Line 63: Line 32:
</syntaxhighlight>
</syntaxhighlight>


If you have nested {{codeline|if}} statements, use extra braces for extra clarification.
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
Split long expressions in such a way that a continuation line starts
Line 112: Line 46:
</syntaxhighlight>
</syntaxhighlight>


==== Optional braces ====
=== Non indenting whitespace ===


Consider putting extra braces around a multi-line expression to make it
Consider putting extra braces around a multi-line expression to make it
Line 118: Line 52:
put extra braces anywhere if it improves clarity.
put extra braces anywhere if it improves clarity.


=== Pointer and Reference appearance ===
The negation operator is written with a space between the operator
and its target, e.g., {{codeline|! A}}.


Declarations of pointers have the '*' character cuddled with the ''name'' of the variable.
Declarations of pointers have the '*' character cuddled with the name of the variable.


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Line 126: Line 61:
</syntaxhighlight>
</syntaxhighlight>


However, references have the '&' character cuddled with the ''type'' of the variable.
However, references have the '&' character cuddled with the type of the variable.


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Line 132: Line 67:
</syntaxhighlight>
</syntaxhighlight>


=== Miscellaneous ===
=== Line Length ===


The negation operator is written with a space between the operator
Keep the length of source lines to 79 characters or less, for maximum
and its target, e.g., {{codeline|! A}}.
readability in the widest range of environments.  This is inherited from
the [https://www.gnu.org/prep/standards/standards.html#Formatting GNU Coding Standards].


=== Function headers ===
=== Function headers ===


In general, in non-header files, format function headers like this:
Format function headers like this:


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Line 149: Line 85:
The return type of the function and any modifiers are specified on the first
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
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
multi-line argument lists should be aligned on the first char after the open
parenthesis.  Put a space before the left open parenthesis and after
parenthesis.  You should put a space before the left open parenthesis and after
commas, for both function definitions and function calls.
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 ===
=== Namespace ===


All code should be in the {{codeline|octave}} namespace or in a namespace below it.
All code should be in the octave namespace.  This is an ongoing project.  We
are still moving existing classes into namespaces but all new classes
should go somewhere into the "octave" namespace.  There is 1 extra level for namespaces
inside octave to be used with care, we don't want too many namespaces.
Ask before creating a new namespace.


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.
* Indent namespaces as any other block.  Emacs and other editors can do this automatically.
* Define namespace on the .cc files;
* Do not use "using X" directives;
* Do not declare anything on the std namespace;


Example
{{Code|namespace style on a .h file|<syntaxhighlight lang="cpp">
 
// Note indentation
{{Code|Use of namespace macros|<syntaxhighlight lang="cpp">
namespace octave
OCTAVE_BEGIN_NAMESPACE(octave)
{
 
  namespace math
OCTAVE_BEGIN_NAMESPACE(math)
  {
 
    class foo
template <typename T>
    {
void
    public:
umfpack_report_control (const double *Control);
      foo (...);
 
    };
OCTAVE_END_NAMESPACE(math)
  }
OCTAVE_END_NAMESPACE(octave)
}
</syntaxhighlight>}}
</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 style on a .cc file|<syntaxhighlight lang="cpp">
 
// Note indentation and that functions are not defined
{{Code|bare namespace usage|<syntaxhighlight lang="cpp">
// as "octave::math::foo:foo"
// Note indentation and that functions are not defined as "octave::math::foo:foo"
namespace octave
namespace octave
{
{
Line 203: Line 131:
}
}
</syntaxhighlight>}}
</syntaxhighlight>}}
==== Other Guidelines ====
* Do not use {{codeline|using XXX;}} directives
* Do not declare anything on the {{codeline|std::}} namespace


== Naming ==
== 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.
Use lowercase names if possible. Uppercase is acceptable for variable
 
names consisting of 1-2 letters. Do not use mixed case 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 260: Line 174:
== C++ features ==
== C++ features ==


=== references ===
=== C++11 features ===
 
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 ()
C++11 features are generally allowed. Check if the feature you want to
{
use has been already used. If not, ask on the mailing list.
  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 ===
=== std::string ===


When an empty string is required, use <code>""</code>, rather than creating an empty
When an empty string is required, use "", rather than creating an empty
string object with <code>std::string ()</code>.
string object with std::string ().


=== auto ===
=== auto ===
Line 365: Line 193:
* 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++ style casting ===
=== C++14 ===
 
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
Do not use C++14 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
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].
An exception: code that requires C++14 feature must also implement an
alternative code in the absence of said feature.  In such case, use a
configure check. This increases maintenance a lot, must be used sparsely,
and requires approval from other maintainers.


<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">
Please note that all contributions to Octave may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see Octave:Copyrights for details). Do not submit copyrighted work without permission!

To edit this page, please answer the question that appears below (more info):

Cancel Editing help (opens in new window)

Templates used on this page: