mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2025-12-18 21:24:41 +03:00
Update of gh-pages text
This commit is contained in:
@@ -4,7 +4,7 @@ layout: default
|
||||
|
||||
# <a name="main"></a> C++ Core Guidelines
|
||||
|
||||
December 12, 2015
|
||||
December 13, 2015
|
||||
|
||||
Editors:
|
||||
|
||||
@@ -769,10 +769,13 @@ There are cases where checking early is dumb because you may not ever need the v
|
||||
|
||||
class Jet { // Physics says: e*e < x*x + y*y + z*z
|
||||
|
||||
float fx, fy, fz, fe;
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float e;
|
||||
public:
|
||||
Jet(float x, float y, float z, float e)
|
||||
:fx(x), fy(y), fz(z), fe(e)
|
||||
:x(x), y(y), z(z), e(e)
|
||||
{
|
||||
// Should I check here that the values are physically meaningful?
|
||||
}
|
||||
@@ -2243,8 +2246,8 @@ When copying is cheap, nothing beats the simplicity and safety of copying, and f
|
||||
|
||||
For advanced uses (only), where you really need to optimize for rvalues passed to "input-only" parameters:
|
||||
|
||||
* If the function is going to unconditionally move from the argument, take it by `&&`. See [F.21](#Rf-consume).
|
||||
* If the function is going to keep a copy of the argument, in addition to passing by `const&` add an overload that passes the parameter by `&&` and in the body `std::move`s it to its destination. Essentially this overloads a "consume"; see [F.21](#Rf-consume).
|
||||
* If the function is going to unconditionally move from the argument, take it by `&&`. See [F.18](#Rf-consume).
|
||||
* If the function is going to keep a copy of the argument, in addition to passing by `const&` add an overload that passes the parameter by `&&` and in the body `std::move`s it to its destination. Essentially this overloads a "consume"; see [F.18](#Rf-consume).
|
||||
* In special cases, such as multiple "input + copy" parameters, consider using perfect forwarding. See [F.19](#Rf-forward).
|
||||
|
||||
##### Example
|
||||
@@ -2347,7 +2350,7 @@ Unique owner types that are move-only and cheap-to-move, such as `unique_ptr`, c
|
||||
|
||||
If the object is to be passed onward to other code and not directly used by this function, we want to make this function agnostic to the argument `const`-ness and rvalue-ness.
|
||||
|
||||
In that case, and only that case, make the parameter `TP&&` where `TP` is a template type parameter -- it both *ignores* and *preserves* `const`-ness and rvalue-ness. Therefore any code that uses a `T&&` is implicitly declaring that it itself doesn't care about the variable's `const`-ness and rvalue-ness (because it is ignored), but that intends to pass the value onward to other code that does care about `const`-ness and rvalue-ness (because it is preserved). When used as a parameter `TP&&` is safe because any temporary objects passed from the caller will live for the duration of the function call. A parameter of type `TP&&` should essentially always be passed onward via `std::forward` in the body of the function.
|
||||
In that case, and only that case, make the parameter `TP&&` where `TP` is a template type parameter -- it both *ignores* and *preserves* `const`-ness and rvalue-ness. Therefore any code that uses a `TP&&` is implicitly declaring that it itself doesn't care about the variable's `const`-ness and rvalue-ness (because it is ignored), but that intends to pass the value onward to other code that does care about `const`-ness and rvalue-ness (because it is preserved). When used as a parameter `TP&&` is safe because any temporary objects passed from the caller will live for the duration of the function call. A parameter of type `TP&&` should essentially always be passed onward via `std::forward` in the body of the function.
|
||||
|
||||
##### Example
|
||||
|
||||
@@ -2423,7 +2426,7 @@ And yes, C++ does have multiple return values, by convention of using a `tuple`,
|
||||
tuple<int, string> f(const string& input) // GOOD: self-documenting
|
||||
{
|
||||
// ...
|
||||
return make_tuple(something(), status);
|
||||
return make_tuple(status, something());
|
||||
}
|
||||
|
||||
In fact, C++98's standard library already used this convenient feature, because a `pair` is like a two-element `tuple`.
|
||||
@@ -2630,7 +2633,7 @@ Using `std::shared_ptr` is the standard way to represent shared ownership. That
|
||||
std::thread t2 {shade, args2, bottom_left, im};
|
||||
std::thread t3 {shade, args3, bottom_right, im};
|
||||
|
||||
// detach treads
|
||||
// detach threads
|
||||
// last thread to finish deletes the image
|
||||
|
||||
##### Note
|
||||
@@ -2852,6 +2855,28 @@ Better:
|
||||
|
||||
Flag any use of `&&` as a return type, except in `std::move` and `std::forward`.
|
||||
|
||||
### <a name="Rf-main"></a> F.46: `int` is the return type for `main()`
|
||||
|
||||
##### Reason
|
||||
|
||||
It's a language rule, but violated through "language extensions" so often that it is worth mentioning.
|
||||
Declaring `main` (the one global `main` of a program) `void` limits portability.
|
||||
|
||||
##### Example
|
||||
|
||||
void main() { /* ... */ }; // bad, not C++
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "This is the way to do it\n";
|
||||
}
|
||||
|
||||
##### Enforcement
|
||||
|
||||
* The compiler should do it
|
||||
* If the compiler doesn't do it, let tools flag it
|
||||
|
||||
|
||||
### <a name="Rf-capture-vs-overload"></a> F.50: Use a lambda when a function won't do (to capture local variables, or to write a local function)
|
||||
|
||||
##### Reason
|
||||
@@ -2885,27 +2910,6 @@ Functions can't capture local variables or be declared at local scope; if you ne
|
||||
* Warn on use of a named non-generic lambda (e.g., `auto x = [](int i){ /*...*/; };`) that captures nothing and appears at global scope. Write an ordinary function instead.
|
||||
|
||||
|
||||
### <a name="Rf-main"></a> F.46: `int` is the return type for `main()`
|
||||
|
||||
##### Reason
|
||||
|
||||
It's a language rule, but violated through "language extensions" so often that it is worth mentioning.
|
||||
Declaring `main` (the one global `main` of a program) `void` limits portability.
|
||||
|
||||
##### Example
|
||||
|
||||
void main() { /* ... */ }; // bad, not C++
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << "This is the way to do it\n";
|
||||
}
|
||||
|
||||
##### Enforcement
|
||||
|
||||
* The compiler should do it
|
||||
* If the compiler doesn't do it, let tools flag it
|
||||
|
||||
### <a name="Rf-default-args"></a> F.51: Prefer overloading over default arguments for virtual functions
|
||||
|
||||
??? possibly other situations?
|
||||
@@ -3202,7 +3206,6 @@ You need a reason (use cases) for using a hierarchy.
|
||||
|
||||
auto p21 = make_unique<Point2>(1, 2); // make an object on the free store
|
||||
auto p22 = p21.clone(); // make a copy
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
@@ -4069,7 +4072,7 @@ A class with members that all have default constructors implicitly gets a defaul
|
||||
vector v;
|
||||
};
|
||||
|
||||
X x; // means X{ {}, {} }; that is the empty string and the empty vector
|
||||
X x; // means X{ {},{} }; that is the empty string and the empty vector
|
||||
|
||||
Beware that built-in types are not properly default constructed:
|
||||
|
||||
@@ -8556,9 +8559,9 @@ A programmer should know and use the basic rules for expressions.
|
||||
|
||||
##### Example
|
||||
|
||||
x = k * y + z; // OK
|
||||
x=k * y + z; // OK
|
||||
|
||||
auto t1 = k * y; // bad: unnecessarily verbose
|
||||
auto t1 = k*y; // bad: unnecessarily verbose
|
||||
x = t1 + z;
|
||||
|
||||
if (0 <= x && x < max) // OK
|
||||
@@ -11188,7 +11191,7 @@ Assume that `Apple` and `Pear` are two kinds of `Fruit`s.
|
||||
void maul(Fruit* p)
|
||||
{
|
||||
*p = Pear{}; // put a Pear into *p
|
||||
p[1] = Pear{}; // put a Pear into p[1]
|
||||
p[1] = Pear{}; // put a Pear into p[2]
|
||||
}
|
||||
|
||||
Apple aa [] = { an_apple, another_apple }; // aa contains Apples (obviously!)
|
||||
@@ -11213,10 +11216,10 @@ Note that `maul()` violates the a `T*` points to an individual object [Rule](#??
|
||||
|
||||
vector<Apple> va = { an_apple, another_apple }; // aa contains Apples (obviously!)
|
||||
|
||||
maul2(va); // error: cannot convert a vector<Apple> to a Fruit*
|
||||
maul2(&va[0]); // you asked for it
|
||||
maul2(aa); // error: cannot convert a vector<Apple> to a Fruit*
|
||||
maul2(&aa[0]); // you asked for it
|
||||
|
||||
Apple& a0 = &va[0]; // a Pear?
|
||||
Apple& a0 = &aa[0]; // a Pear?
|
||||
|
||||
Note that the assignment in `maul2()` violated the no-slicing [Rule](#???).
|
||||
|
||||
@@ -13009,7 +13012,7 @@ This is not evil.
|
||||
|
||||
Some styles distinguishes types from non-types.
|
||||
|
||||
template<typename T>
|
||||
typename<typename T>
|
||||
class Hash_tbl { // maps string to T
|
||||
// ...
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user