mirror of
https://github.com/cpp-best-practices/cppbestpractices.git
synced 2025-12-17 11:14:35 +03:00
Edit style section for grammar and clarity
I added a few missing punctuations and cleaned up the wording in a few places to make it a little clearer. I fixed the name of the constructor in a couple of the code examples.
This commit is contained in:
91
03-Style.md
91
03-Style.md
@@ -1,8 +1,8 @@
|
||||
# Style
|
||||
|
||||
Consistency of style is more important. Second most importance is following a style that the average C++ programmer is used to reading.
|
||||
Consistency is the most important aspect of style. The second most important aspect is following a style that the average C++ programmer is used to reading.
|
||||
|
||||
C++ allows for arbitrary-length identifier names, so there's no reason to be terse when naming variables. Use descriptive names, and be consistent in the style.
|
||||
C++ allows for arbitrary-length identifier names, so there's no reason to be terse when naming things. Use descriptive names, and be consistent in the style.
|
||||
|
||||
* `CamelCase`
|
||||
* `snake_case`
|
||||
@@ -11,27 +11,27 @@ are common examples. *snake_case* has the advantage that it can also work with s
|
||||
|
||||
## Common C++ Naming Conventions
|
||||
|
||||
* Types start with capitals: `MyClass`
|
||||
* functions and variables start with lower case: `myMethod`
|
||||
* constants are all capital: `const double PI=3.14159265358979323;`
|
||||
* Types start with upper case: `MyClass`.
|
||||
* Functions and variables start with lower case: `myMethod`.
|
||||
* Constants are all upper case: `const double PI=3.14159265358979323;`.
|
||||
|
||||
C++ Standard Library (and other well-known C++ libraries like [Boost](http://www.boost.org/)) use these guidelines:
|
||||
|
||||
* Macro names use uppercase with underscores: `INT_MAX`
|
||||
* Template parameter names use camel case: `InputIterator`
|
||||
* All other names use snake case: `unordered_map`
|
||||
* Macro names use upper case with underscores: `INT_MAX`.
|
||||
* Template parameter names use camel case: `InputIterator`.
|
||||
* All other names use snake case: `unordered_map`.
|
||||
|
||||
## Distinguish Private Object Data
|
||||
|
||||
Name private data with a `m_` prefix to distinguish it from public data. `m_` stands for "member" data
|
||||
Name private data with a `m_` prefix to distinguish it from public data. `m_` stands for "member" data.
|
||||
|
||||
## Distinguish Function Parameters
|
||||
|
||||
The most important thing is consistency within your codebase, this is one possibility to help with consistency.
|
||||
The most important thing is consistency within your codebase; this is one possibility to help with consistency.
|
||||
|
||||
Name function parameters with an `t_` prefix. `t_` can be thought of as "the", but the meaning is arbitrary. The point is to distinguish function parameters from other variables in scope while giving us a consistent naming strategy.
|
||||
|
||||
By using `t_` for parameters and `m_` for module data, we can have consistency with both public members of structs and private members of classes.
|
||||
By using `t_` for parameters and `m_` for member data, we can have consistency with both public members of structs and private members of classes.
|
||||
|
||||
Any prefix or postfix can be chosen for your organization. This is just one example. *This suggestion is controversial, for a discussion about it see issue [#11](https://github.com/lefticus/cppbestpractices/issues/11).*
|
||||
|
||||
@@ -41,17 +41,17 @@ struct Size
|
||||
int width;
|
||||
int height;
|
||||
|
||||
ValueType(int t_width, int t_height) : width(t_width), height(t_height) {}
|
||||
Size(int t_width, int t_height) : width(t_width), height(t_height) {}
|
||||
};
|
||||
|
||||
// this version might make sense for thread safety or something,
|
||||
// but more to the point, sometimes we need to hide data, sometimes we don't
|
||||
// This version might make sense for thread safety or something,
|
||||
// but more to the point, sometimes we need to hide data, sometimes we don't.
|
||||
class PrivateSize
|
||||
{
|
||||
public:
|
||||
int width() const { return m_width; }
|
||||
int height() const { return m_height; }
|
||||
ValueType(int t_width, int t_height) : m_width(t_width), m_height(t_height) {}
|
||||
PrivateSize(int t_width, int t_height) : m_width(t_width), m_height(t_height) {}
|
||||
|
||||
private:
|
||||
int m_width;
|
||||
@@ -64,7 +64,7 @@ class PrivateSize
|
||||
|
||||
## Don't Name Anything Starting With `_`
|
||||
|
||||
If you do, you risk broaching on names reserved for implementation use:
|
||||
If you do, you risk colliding with names reserved for compiler and standard library implementation use:
|
||||
|
||||
http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier
|
||||
|
||||
@@ -94,12 +94,12 @@ private:
|
||||
|
||||
## Enable Out-of-Source-Directory Builds
|
||||
|
||||
Make sure generated files go into build folder, not the source folder
|
||||
Make sure generated files go into an output folder that is separate from the source folder.
|
||||
|
||||
|
||||
## Use `nullptr`
|
||||
|
||||
C++11 introduces `nullptr` which is a special type denoting a null pointer value. This should be used instead of `0` or `NULL` to indicate a null pointer.
|
||||
C++11 introduces `nullptr` which is a special value denoting a null pointer. This should be used instead of `0` or `NULL` to indicate a null pointer.
|
||||
|
||||
## Comments
|
||||
|
||||
@@ -123,12 +123,12 @@ int myFunc()
|
||||
*/
|
||||
```
|
||||
|
||||
which would be impossible if the function comment header used `/* */`
|
||||
which would be impossible if the function comment header used `/* */`.
|
||||
|
||||
## Never Use `using namespace` in a Header File
|
||||
|
||||
This causes the name space you are `using` to be pulled into the namespace of the header file.
|
||||
It litters the namespace and it may lead to name collisions in the future.
|
||||
This causes the namespace you are `using` to be pulled into the namespace of all files that include the header file.
|
||||
It pollutes the namespace and it may lead to name collisions in the future.
|
||||
Writing `using namespace` in an implementation file is fine though.
|
||||
|
||||
|
||||
@@ -157,13 +157,14 @@ Leaving them off can lead to semantic errors in the code.
|
||||
|
||||
```cpp
|
||||
// Bad Idea
|
||||
// this compiles and does what you want, but can lead to confusing
|
||||
// errors if close attention is not paid.
|
||||
// This compiles and does what you want, but can lead to confusing
|
||||
// errors if modification are made in the future and close attention
|
||||
// is not paid.
|
||||
for (int i = 0; i < 15; ++i)
|
||||
std::cout << i << std::endl;
|
||||
|
||||
// Bad Idea
|
||||
// the cout is not part of the loop in this case even though it appears to be
|
||||
// The cout is not part of the loop in this case even though it appears to be.
|
||||
int sum = 0;
|
||||
for (int i = 0; i < 15; ++i)
|
||||
++sum;
|
||||
@@ -171,7 +172,7 @@ for (int i = 0; i < 15; ++i)
|
||||
|
||||
|
||||
// Good Idea
|
||||
// It's clear which statements are part of the loop (or if block, or whatever)
|
||||
// It's clear which statements are part of the loop (or if block, or whatever).
|
||||
int sum = 0;
|
||||
for (int i = 0; i < 15; ++i) {
|
||||
++sum;
|
||||
@@ -205,26 +206,26 @@ It also makes it possible to have two separate files next to each other on one s
|
||||
|
||||
```cpp
|
||||
// Bad Idea. Requires extra -I directives to the compiler
|
||||
// and goes against standards
|
||||
// and goes against standards.
|
||||
#include <string>
|
||||
#include <includes/MyHeader.hpp>
|
||||
|
||||
// Worse Idea
|
||||
// requires potentially even more specific -I directives and
|
||||
// makes code more difficult to package and distribute
|
||||
// Requires potentially even more specific -I directives and
|
||||
// makes code more difficult to package and distribute.
|
||||
#include <string>
|
||||
#include <MyHeader.hpp>
|
||||
|
||||
|
||||
// Good Idea
|
||||
// requires no extra params and notifies the user that the file
|
||||
// is a local file
|
||||
// Requires no extra params and notifies the user that the file
|
||||
// is a local file.
|
||||
#include <string>
|
||||
#include "MyHeader.hpp"
|
||||
```
|
||||
|
||||
## Initialize Member Variables
|
||||
...with the member initializer list
|
||||
...with the member initializer list.
|
||||
|
||||
```cpp
|
||||
// Bad Idea
|
||||
@@ -244,7 +245,7 @@ private:
|
||||
// Good Idea
|
||||
// C++'s member initializer list is unique to the language and leads to
|
||||
// cleaner code and potential performance gains that other languages cannot
|
||||
// match
|
||||
// match.
|
||||
class MyClass
|
||||
{
|
||||
public:
|
||||
@@ -267,7 +268,7 @@ private:
|
||||
```
|
||||
inside the class body. This makes sure that no constructor ever "forgets" to initialize a member object.
|
||||
|
||||
Use brace initialization, it does not allow narrowing at compile-time:
|
||||
Use brace initialization; it does not allow narrowing at compile-time:
|
||||
```cpp
|
||||
// Best Idea
|
||||
|
||||
@@ -283,16 +284,16 @@ Forgetting to initialize a member is a source of undefined behavior bugs which a
|
||||
|
||||
## Always Use Namespaces
|
||||
|
||||
There is almost never a reason to declare an identifier in the global namespaces. Instead, functions and classes should exist in an appropriately named namespace or in a class inside of a namespace. Identifiers which are placed in the global namespace risk conflicting with identifiers from other libraries (mostly C, which doesn't have namespaces).
|
||||
There is almost never a reason to declare an identifier in the global namespace. Instead, functions and classes should exist in an appropriately named namespace or in a class inside of a namespace. Identifiers which are placed in the global namespace risk conflicting with identifiers from other libraries (mostly C, which doesn't have namespaces).
|
||||
|
||||
|
||||
## Use the Correct Integer Type For stdlib Features
|
||||
## Use the Correct Integer Type for Standard Library Features
|
||||
|
||||
The standard library generally returns `size_t` for anything related to size. What exactly `size_t` is, is implementation defined.
|
||||
The standard library generally uses `std::size_t` for anything related to size. The size of `size_t` is implementation defined.
|
||||
|
||||
In general, using `auto` will avoid most of these issues, but not all.
|
||||
|
||||
Make sure you stick with the correct integer types and remain consistent with the C++ stdlib. It might not warn on the platform you are currently using, but it probably will when you change platforms.
|
||||
Make sure you stick with the correct integer types and remain consistent with the C++ standard library. It might not warn on the platform you are currently using, but it probably will when you change platforms.
|
||||
|
||||
## Use .hpp and .cpp for Your File Extensions
|
||||
|
||||
@@ -302,7 +303,7 @@ One particularly large project ([OpenStudio](https://github.com/NREL/OpenStudio)
|
||||
|
||||
## Never Mix Tabs and Spaces
|
||||
|
||||
Some editors like to indent with a mixture of tabs and spaces by default. This makes the code unreadable to anyone not using the exact same tab indentation settings.
|
||||
Some editors like to indent with a mixture of tabs and spaces by default. This makes the code unreadable to anyone not using the exact same tab indentation settings. Configure your editor so this does not happen.
|
||||
|
||||
## Never Put Code with Side Effects Inside an assert()
|
||||
|
||||
@@ -322,17 +323,17 @@ They should be preferred to macros, because macros do not honor namespaces, etc.
|
||||
|
||||
Operator overloading was invented to enable expressive syntax. Expressive in the sense that adding two big integers looks like `a + b` and not `a.add(b)`. Another common example is std::string, where it is very common to concatenate two strings with `string1 + string2`.
|
||||
|
||||
However, you can easily create unreadable expressions using too much or wrong operator overloading. When overloading operators, there are three basic rules to follow as described [on stackoverflow](http://stackoverflow.com/questions/4421706/operator-overloading/4421708#4421708)
|
||||
However, you can easily create unreadable expressions using too much or wrong operator overloading. When overloading operators, there are three basic rules to follow as described [on stackoverflow](http://stackoverflow.com/questions/4421706/operator-overloading/4421708#4421708).
|
||||
|
||||
More detailed, you should keep these things in mind:
|
||||
Specifically, you should keep these things in mind:
|
||||
|
||||
* Overloading `operator=` when handling with resources is a must, see [Consider the Rule of Zero](03-Style.md#consider-the-rule-of-zero) below.
|
||||
* Overloading `operator=()` when handling resources is a must. See [Consider the Rule of Zero](03-Style.md#consider-the-rule-of-zero) below.
|
||||
* For all other operators, only overload them when they are used in a context that is commonly connected to these operators. Typical scenarios are concatenating things with +, negating expressions that can be considered "true" or "false", etc.
|
||||
* Always be aware of the [operator precedence](http://en.cppreference.com/w/cpp/language/operator_precedence) and try to circumvent unintuitive constructs.
|
||||
* Always be aware of the [operator precedence](http://en.cppreference.com/w/cpp/language/operator_precedence) and try to circumvent unintuitive constructs.
|
||||
* Do not overload exotic operators such as ~ or % unless implementing a numeric type or following a well recognized syntax in specific domain.
|
||||
* [Never](http://stackoverflow.com/questions/5602112/when-to-overload-the-comma-operator?answertab=votes#tab-top) overload `operator ,` (the comma operator).
|
||||
* Use `operator >>` and `operator <<` when dealing with streams. For example, you can overload `operator <<(std::ostream &, MyClass const &)` to enable "writing" you class into a stream, such as std::cout or an std::fstream or std::stringstream. The latter is often used to create a textual representation of a value.
|
||||
* There are more common operators to overload [described here](http://stackoverflow.com/questions/4421706/operator-overloading?answertab=votes#tab-top)
|
||||
* [Never](http://stackoverflow.com/questions/5602112/when-to-overload-the-comma-operator?answertab=votes#tab-top) overload `operator,()` (the comma operator).
|
||||
* Use non-member functions `operator>>()` and `operator<<()` when dealing with streams. For example, you can overload `operator<<(std::ostream &, MyClass const &)` to enable "writing" your class into a stream, such as `std::cout` or an `std::fstream` or `std::stringstream`. The latter is often used to create a string representation of a value.
|
||||
* There are more common operators to overload [described here](http://stackoverflow.com/questions/4421706/operator-overloading?answertab=votes#tab-top).
|
||||
|
||||
More tips regarding the implementation details of your custom operators can be found [here](http://courses.cms.caltech.edu/cs11/material/cpp/donnie/cpp-ops.html).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user