mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2024-03-22 13:30:58 +08:00
style: fix code indentation
This commit is contained in:
parent
67191255fa
commit
5aea4a1fef
|
@ -523,8 +523,8 @@ Some language constructs express intent better than others.
|
||||||
|
|
||||||
If two `int`s are meant to be the coordinates of a 2D point, say so:
|
If two `int`s are meant to be the coordinates of a 2D point, say so:
|
||||||
|
|
||||||
draw_line(int, int, int, int); // obscure
|
draw_line(int, int, int, int); // obscure
|
||||||
draw_line(Point, Point); // clearer
|
draw_line(Point, Point); // clearer
|
||||||
|
|
||||||
##### Enforcement
|
##### Enforcement
|
||||||
|
|
||||||
|
@ -3287,16 +3287,16 @@ This was primarily to avoid code of the form `(a = b) = c` -- such code is not c
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
class Foo
|
class Foo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
...
|
...
|
||||||
Foo& operator=(const Foo& rhs) {
|
Foo& operator=(const Foo& rhs) {
|
||||||
// Copy members.
|
// Copy members.
|
||||||
...
|
...
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
##### Enforcement
|
##### Enforcement
|
||||||
|
|
||||||
|
@ -4653,16 +4653,16 @@ A class with members that all have default constructors implicitly gets a defaul
|
||||||
Beware that built-in types are not properly default constructed:
|
Beware that built-in types are not properly default constructed:
|
||||||
|
|
||||||
struct X {
|
struct X {
|
||||||
string s;
|
string s;
|
||||||
int i;
|
int i;
|
||||||
};
|
};
|
||||||
|
|
||||||
void f()
|
void f()
|
||||||
{
|
{
|
||||||
X x; // x.s is initialized to the empty string; x.i is uninitialized
|
X x; // x.s is initialized to the empty string; x.i is uninitialized
|
||||||
|
|
||||||
cout << x.s << ' ' << x.i << '\n';
|
cout << x.s << ' ' << x.i << '\n';
|
||||||
++x.i;
|
++x.i;
|
||||||
}
|
}
|
||||||
|
|
||||||
Statically allocated objects of built-in types are by default initialized to `0`, but local built-in variables are not.
|
Statically allocated objects of built-in types are by default initialized to `0`, but local built-in variables are not.
|
||||||
|
@ -4671,8 +4671,8 @@ Thus, code like the example above may appear to work, but it relies on undefined
|
||||||
Assuming that you want initialization, an explicit default initialization can help:
|
Assuming that you want initialization, an explicit default initialization can help:
|
||||||
|
|
||||||
struct X {
|
struct X {
|
||||||
string s;
|
string s;
|
||||||
int i {}; // default initialize (to 0)
|
int i {}; // default initialize (to 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
##### Enforcement
|
##### Enforcement
|
||||||
|
@ -5960,7 +5960,7 @@ Interfaces should normally be composed entirely of public pure virtual functions
|
||||||
unique_ptr<Goof> p {new Derived{"here we go"}};
|
unique_ptr<Goof> p {new Derived{"here we go"}};
|
||||||
f(p.get()); // use Derived through the Goof interface
|
f(p.get()); // use Derived through the Goof interface
|
||||||
g(p.get()); // use Derived through the Goof interface
|
g(p.get()); // use Derived through the Goof interface
|
||||||
} // leak
|
} // leak
|
||||||
|
|
||||||
The `Derived` is `delete`d through its `Goof` interface, so its `string` is leaked.
|
The `Derived` is `delete`d through its `Goof` interface, so its `string` is leaked.
|
||||||
Give `Goof` a virtual destructor and all is well.
|
Give `Goof` a virtual destructor and all is well.
|
||||||
|
@ -6176,8 +6176,8 @@ the more benefits we gain - and the less stable the hierarchy is.
|
||||||
|
|
||||||
This Shape hierarchy can be rewritten using interface inheritance:
|
This Shape hierarchy can be rewritten using interface inheritance:
|
||||||
|
|
||||||
class Shape { // pure interface
|
class Shape { // pure interface
|
||||||
public:
|
public:
|
||||||
virtual Point center() const = 0;
|
virtual Point center() const = 0;
|
||||||
virtual Color color() const = 0;
|
virtual Color color() const = 0;
|
||||||
|
|
||||||
|
@ -6187,7 +6187,7 @@ This Shape hierarchy can be rewritten using interface inheritance:
|
||||||
virtual void redraw() = 0;
|
virtual void redraw() = 0;
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
};
|
};
|
||||||
|
|
||||||
Note that a pure interface rarely have constructors: there is nothing to construct.
|
Note that a pure interface rarely have constructors: there is nothing to construct.
|
||||||
|
|
||||||
|
@ -6256,8 +6256,8 @@ Now `Shape` is a poor example of a class with an implementation,
|
||||||
but bear with us because this is just a simple example of a technique aimed at more complex hierarchies.
|
but bear with us because this is just a simple example of a technique aimed at more complex hierarchies.
|
||||||
|
|
||||||
|
|
||||||
class Impl::Circle : public Circle, public Impl::Shape { // implementation
|
class Impl::Circle : public Circle, public Impl::Shape { // implementation
|
||||||
public:
|
public:
|
||||||
// constructors, destructor
|
// constructors, destructor
|
||||||
|
|
||||||
int radius() { /* ... */ }
|
int radius() { /* ... */ }
|
||||||
|
@ -8801,7 +8801,7 @@ comment.
|
||||||
|
|
||||||
##### Example, bad
|
##### Example, bad
|
||||||
|
|
||||||
char *p, c, a[7], *pp[7], **aa[10]; // yuck!
|
char *p, c, a[7], *pp[7], **aa[10]; // yuck!
|
||||||
|
|
||||||
**Exception**: a function declaration can contain several function argument declarations.
|
**Exception**: a function declaration can contain several function argument declarations.
|
||||||
|
|
||||||
|
@ -9124,8 +9124,8 @@ The rules for `{}` initialization are simpler, more general, less ambiguous, and
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
int x {f(99)};
|
int x {f(99)};
|
||||||
vector<int> v = {1, 2, 3, 4, 5, 6};
|
vector<int> v = {1, 2, 3, 4, 5, 6};
|
||||||
|
|
||||||
##### Exception
|
##### Exception
|
||||||
|
|
||||||
|
@ -9590,15 +9590,15 @@ Readability: the complete logic of the loop is visible "up front". The scope of
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
for (int i = 0; i < vec.size(); i++) {
|
for (int i = 0; i < vec.size(); i++) {
|
||||||
// do work
|
// do work
|
||||||
}
|
}
|
||||||
|
|
||||||
##### Example, bad
|
##### Example, bad
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (i < vec.size()) {
|
while (i < vec.size()) {
|
||||||
// do work
|
// do work
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
##### Enforcement
|
##### Enforcement
|
||||||
|
@ -10799,7 +10799,7 @@ the same memory. Concurrent programming is tricky for many reasons, most
|
||||||
importantly that it is undefined behavior to read data in one thread after it
|
importantly that it is undefined behavior to read data in one thread after it
|
||||||
was written by another thread, if there is no proper synchronization between
|
was written by another thread, if there is no proper synchronization between
|
||||||
those threads. Making existing single-threaded code execute concurrently can be
|
those threads. Making existing single-threaded code execute concurrently can be
|
||||||
as trivial as adding `std::async` or `std::thread` strategically, or it can
|
as trivial as adding `std::async` or `std::thread` strategically, or it can
|
||||||
necessitate a full rewrite, depending on whether the original code was written
|
necessitate a full rewrite, depending on whether the original code was written
|
||||||
in a thread-friendly way.
|
in a thread-friendly way.
|
||||||
|
|
||||||
|
@ -11276,7 +11276,7 @@ If a `thread` joins, we can safely pass pointers to objects in the scope of the
|
||||||
auto q = make_unique<int>(99);
|
auto q = make_unique<int>(99);
|
||||||
raii_thread t3(f, q.get()); // OK
|
raii_thread t3(f, q.get()); // OK
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
An `raii_thread` is a `std::thread` with a destructor that joined and cannot be `detached()`.
|
An `raii_thread` is a `std::thread` with a destructor that joined and cannot be `detached()`.
|
||||||
By "OK" we mean that the object will be in scope ("live") for as long as a `thread` can use the pointer to it.
|
By "OK" we mean that the object will be in scope ("live") for as long as a `thread` can use the pointer to it.
|
||||||
|
@ -11321,7 +11321,7 @@ If a `thread` is detached, we can safely pass pointers to static and free store
|
||||||
t2.detach();
|
t2.detach();
|
||||||
t3.detach();
|
t3.detach();
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
By "OK" we mean that the object will be in scope ("live") for as long as a `thread` can use the pointers to it.
|
By "OK" we mean that the object will be in scope ("live") for as long as a `thread` can use the pointers to it.
|
||||||
By "bad" we mean that a `thread` may use a pointer after the pointed-to object is destroyed.
|
By "bad" we mean that a `thread` may use a pointer after the pointed-to object is destroyed.
|
||||||
|
@ -11567,7 +11567,7 @@ Thread creation is expensive.
|
||||||
|
|
||||||
void master(istream& is)
|
void master(istream& is)
|
||||||
{
|
{
|
||||||
for (Message m; is >> m; )
|
for (Message m; is >> m; )
|
||||||
run_list.push_back(new thread(worker, m));
|
run_list.push_back(new thread(worker, m));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11579,14 +11579,14 @@ Instead, we could have a set of pre-created worker threads processing the messag
|
||||||
|
|
||||||
void master(istream& is)
|
void master(istream& is)
|
||||||
{
|
{
|
||||||
for (Message m; is >> m; )
|
for (Message m; is >> m; )
|
||||||
work.put(n);
|
work.put(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
void worker()
|
void worker()
|
||||||
{
|
{
|
||||||
for (Message m; m = work.get(); ) {
|
for (Message m; m = work.get(); ) {
|
||||||
// process
|
// process
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12752,20 +12752,20 @@ In such cases, "crashing" is simply leaving error handling to the next level of
|
||||||
|
|
||||||
void f(int n)
|
void f(int n)
|
||||||
{
|
{
|
||||||
// ...
|
// ...
|
||||||
p = static_cast<X*>(malloc(n, X));
|
p = static_cast<X*>(malloc(n, X));
|
||||||
if (p == nullptr) abort(); // abort if memory is exhausted
|
if (p == nullptr) abort(); // abort if memory is exhausted
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
Most programs cannot handle memory exhaustion gracefully anyway. This is roughly equivalent to
|
Most programs cannot handle memory exhaustion gracefully anyway. This is roughly equivalent to
|
||||||
|
|
||||||
void f(int n)
|
void f(int n)
|
||||||
{
|
{
|
||||||
// ...
|
// ...
|
||||||
p = new X[n]; // throw if memory is exhausted (by default, terminate)
|
p = new X[n]; // throw if memory is exhausted (by default, terminate)
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
Typically, it is a good idea to log the reason for the "crash" before exiting.
|
Typically, it is a good idea to log the reason for the "crash" before exiting.
|
||||||
|
|
||||||
|
@ -14230,7 +14230,7 @@ Semiregular requires default constructible.
|
||||||
vector<int> v(10);
|
vector<int> v(10);
|
||||||
bool b = 1 == bad;
|
bool b = 1 == bad;
|
||||||
bool b2 = v.size() == bad;
|
bool b2 = v.size() == bad;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
This prints `T0` and `Bad`.
|
This prints `T0` and `Bad`.
|
||||||
|
@ -14587,27 +14587,27 @@ When `concept`s become widely available such alternatives can be distinguished d
|
||||||
|
|
||||||
There are three major ways to let calling code customize a template.
|
There are three major ways to let calling code customize a template.
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
// Call a member function
|
// Call a member function
|
||||||
void test1(T t)
|
void test1(T t)
|
||||||
{
|
{
|
||||||
t.f(); // require T to provide f()
|
t.f(); // require T to provide f()
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void test2(T t)
|
void test2(T t)
|
||||||
// Call a nonmember function without qualification
|
// Call a nonmember function without qualification
|
||||||
{
|
{
|
||||||
f(t); // require f(/*T*/) be available in caller's scope or in T's namespace
|
f(t); // require f(/*T*/) be available in caller's scope or in T's namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void test3(T t)
|
void test3(T t)
|
||||||
// Invoke a "trait"
|
// Invoke a "trait"
|
||||||
{
|
{
|
||||||
test_traits<T>::f(t); // require customizing test_traits<>
|
test_traits<T>::f(t); // require customizing test_traits<>
|
||||||
// to get non-default functions/types
|
// to get non-default functions/types
|
||||||
}
|
}
|
||||||
|
|
||||||
A trait is usually a type alias to compute a type,
|
A trait is usually a type alias to compute a type,
|
||||||
a `constexpr` function to compute a value,
|
a `constexpr` function to compute a value,
|
||||||
|
@ -16291,10 +16291,10 @@ Candidates include:
|
||||||
|
|
||||||
To suppress enforcement of a profile check, place a `suppress` annotation on a language contract. For example:
|
To suppress enforcement of a profile check, place a `suppress` annotation on a language contract. For example:
|
||||||
|
|
||||||
[[suppress(bounds)]] char* raw_find(char* p, int n, char x) // find x in p[0]..p[n-1]
|
[[suppress(bounds)]] char* raw_find(char* p, int n, char x) // find x in p[0]..p[n-1]
|
||||||
{
|
{
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
Now `raw_find()` can scramble memory to its heart's content.
|
Now `raw_find()` can scramble memory to its heart's content.
|
||||||
Obviously, suppression should be very rare.
|
Obviously, suppression should be very rare.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user