C++ Coding Standards

Link to discussion forum: https://community.openpbs.org/t/openpbss-c-coding-standards/2315

 

This will be added to https://openpbs.atlassian.net/wiki/spaces/DG/pages/1481670667

Follow the C Coding Standards, then look here for C++ specific guidelines.

File Extensions

Source files should use .cpp
Header files should use .hpp

Because we a mixed C/C++ project, it is helpful to know which header files we can use in a C file. Therefore, a C header should have a different extension than a C++ header.

.hpp is chosen because it easily attributed to .cpp files.

From the Boost FAQ:

File extensions communicate the "type" of the file, both to humans and to computer programs. The '.h' extension is used for C header files, and therefore communicates the wrong thing about C++ header files... Using '.hpp' unambiguously identifies it as C++ header file, and works well in actual practice. (Rainer Deyke)

Whitespace

We use tabs to be consistent with our C code.

Because we use tabs, we can’t use partial indents.
We don’t want to have a ton of horizontal white space making our lines longer than it has to be.

Classes will not have an indent before public, protected and private

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // Bad class MyClass { public: MyClass(); ~MyClass(); private: int count; }; // Good class MyClass { public: MyClass(); ~MyClass(); private: int count; };

Namespaces will not cause a level of indentation

1 2 3 4 5 6 namespace pbs { // Bad int add(int x, int y); // Good int add(int x, int y); }

Names and Orders of Includes

  1. pbs_config.h if needed

  2. System and STL headers

  3. pbs headers

Some good things to keep in mind

Casting

Do not use C-style casts; instead use C++ style casts.

1 2 3 4 // Bad int *p = (int *)malloc(sizeof(int)); // Good int *p = static_cast<int *>(malloc(sizeof(int)));

Note: Void pointers can't be assigned to non-void pointers without a cast.

Use const char * whenever possible

If you're not changing a char * argument, use const in the function definition

1 2 3 4 5 6 7 8 9 10 11 12 13 14 // Bad void logmsg(int sev, char *msg) { printf("%d\t%s\n", sev, msg); return; } // Good void logmsg(int sev, const char *msg) { printf("%d\t%s\n", sev, msg); return; }

Prefer nullptr to NULL

NULL is often just defined 0, nullptr is a pointer type pointing to the address 0x0.

1 2 3 4 // Bad int *p = NULL; // Good int *p = nullptr;

auto is awesome

A lot of types can be very long strings, such as classes with templates. auto lets you save some typing by deducing the type from the right-hand-side.

1 2 3 4 // bad std::vector<MyClass> list = std::vector<MyClass>(); // good auto list2 = std::vector<MyClass>();

Namespaces

Using using namespace <name> is not a good idea, as it can pollute the global namespace. Instead, use the namespace prefix.

1 2 3 4 5 // Bad using namespace std; auto vec = vector<int>(); // Good auto vec = std::vector<int>();

If you’re in the pbs namespace, don’t create another namespace prefixed with pbs_

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // Bad namespace pbs { namespace pbs_util { int count_spaces(const char *); } } int spaces = pbs::pbs_util::count_spaces(" "); // Good namespace pbs{ namespace util { int count_spaces(const char *); } } int spaces = pbs::util::count_spaces(" ");

Unique Pointers

You can find an example of unique pointers here: https://openpbs.atlassian.net/wiki/spaces/PD/pages/2172551169

Inheritance/Polymorphism

You can find an example of these OOP features here: https://openpbs.atlassian.net/wiki/spaces/PD/pages/2191458305