Skip to content

Commit

Permalink
book: formatting style updates (changkun#231)
Browse files Browse the repository at this point in the history
  • Loading branch information
ambiguoustexture authored Jul 17, 2022
1 parent 41b88c8 commit e50e3c6
Show file tree
Hide file tree
Showing 10 changed files with 106 additions and 76 deletions.
6 changes: 4 additions & 2 deletions book/en-us/02-usability.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ int main() {
}

// should output: 1, 4, 3, 4. can be simplified using `auto`
for (std::vector<int>::iterator element = vec.begin(); element != vec.end(); ++element)
for (std::vector<int>::iterator element = vec.begin(); element != vec.end();
++element)
std::cout << *element << std::endl;
}
```
Expand Down Expand Up @@ -301,7 +302,8 @@ int main() {
MagicFoo magicFoo = {1, 2, 3, 4, 5};

std::cout << "magicFoo: ";
for (std::vector<int>::iterator it = magicFoo.vec.begin(); it != magicFoo.vec.end(); ++it)
for (std::vector<int>::iterator it = magicFoo.vec.begin();
it != magicFoo.vec.end(); ++it)
std::cout << *it << std::endl;
}
```
Expand Down
12 changes: 7 additions & 5 deletions book/en-us/03-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,8 @@ int foo(int a, int b, int c) {
;
}
int main() {
// bind parameter 1, 2 on function foo, and use std::placeholders::_1 as placeholder
// for the first parameter.
// bind parameter 1, 2 on function foo,
// and use std::placeholders::_1 as placeholder for the first parameter.
auto bindFoo = std::bind(foo, std::placeholders::_1, 1,2);
// when call bindFoo, we only need one param left
bindFoo(1);
Expand Down Expand Up @@ -355,7 +355,8 @@ int main()
std::string&& rv1 = std::move(lv1); // legal, std::move can convert lvalue to rvalue
std::cout << rv1 << std::endl; // string,

const std::string& lv2 = lv1 + lv1; // legal, const lvalue reference can extend temp variable's lifecycle
const std::string& lv2 = lv1 + lv1; // legal, const lvalue reference can
// extend temp variable's lifecycle
// lv2 += "Test"; // illegal, const ref can't be modified
std::cout << lv2 << std::endl; // string,string,

Expand Down Expand Up @@ -482,8 +483,9 @@ int main() {
// "str: Hello world."
std::cout << "str: " << str << std::endl;

// use push_back(const T&&), no copy
// the string will be moved to vector, and therefore std::move can reduce copy cost
// use push_back(const T&&),
// no copy the string will be moved to vector,
// and therefore std::move can reduce copy cost
v.push_back(std::move(str));
// str is empty now
std::cout << "str: " << str << std::endl;
Expand Down
14 changes: 7 additions & 7 deletions book/en-us/05-pointers.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,35 +57,35 @@ And see the reference count of an object by `use_count()`. E.g:
auto pointer = std::make_shared<int>(10);
auto pointer2 = pointer; // reference count+1
auto pointer3 = pointer; // reference count+1
int *p = pointer.get(); // no increase of reference count
int *p = pointer.get(); // no increase of reference count
std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 3
std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 3
std::cout << "pointer2.use_count() = " << pointer2.use_count() << std::endl; // 3
std::cout << "pointer3.use_count() = " << pointer3.use_count() << std::endl; // 3
pointer2.reset();
std::cout << "reset pointer2:" << std::endl;
std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 2
std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 2
std::cout << "pointer2.use_count() = "
<< pointer2.use_count() << std::endl; // 0, pointer2 has reset
<< pointer2.use_count() << std::endl; // pointer2 has reset, 0
std::cout << "pointer3.use_count() = " << pointer3.use_count() << std::endl; // 2
pointer3.reset();
std::cout << "reset pointer3:" << std::endl;
std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 1
std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 1
std::cout << "pointer2.use_count() = " << pointer2.use_count() << std::endl; // 0
std::cout << "pointer3.use_count() = "
<< pointer3.use_count() << std::endl; // 0, pointer3 has reset
<< pointer3.use_count() << std::endl; // pointer3 has reset, 0
```

## 5.3 `std::unique_ptr`

`std::unique_ptr` is an exclusive smart pointer that prohibits other smart pointers from sharing the same object, thus keeping the code safe:

```cpp
std::unique_ptr<int> pointer = std::make_unique<int>(10); // make_unique was introduced in C++14
std::unique_ptr<int> pointer = std::make_unique<int>(10); // make_unique, from C++14
std::unique_ptr<int> pointer2 = pointer; // illegal
```

Expand Down
50 changes: 28 additions & 22 deletions book/en-us/06-regex.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,9 @@ We use a simple example to briefly introduce the use of this library. Consider t

int main() {
std::string fnames[] = {"foo.txt", "bar.txt", "test", "a0.txt", "AAA.txt"};
// In C++, `\` will be used as an escape character in the string. In order for `\.`
// to be passed as a regular expression, it is necessary to perform second escaping of `\`, thus we have `\\.`
// In C++, `\` will be used as an escape character in the string.
// In order for `\.` to be passed as a regular expression,
// it is necessary to perform second escaping of `\`, thus we have `\\.`
std::regex txt_regex("[a-z]+\\.txt");
for (const auto &fname: fnames)
std::cout << fname << ": " << std::regex_match(fname, txt_regex) << std::endl;
Expand All @@ -104,7 +105,8 @@ std::smatch base_match;
for(const auto &fname: fnames) {
if (std::regex_match(fname, base_match, base_regex)) {
// the first element of std::smatch matches the entire string
// the second element of std::smatch matches the first expression with brackets
// the second element of std::smatch matches the first expression
// with brackets
if (base_match.size() == 2) {
std::string base = base_match[1].str();
std::cout << "sub-match[0]: " << base_match[0].str() << std::endl;
Expand Down Expand Up @@ -187,32 +189,36 @@ Please implement the member functions `start()` and `parse_request`. Enable serv
template<typename SERVER_TYPE>
void start_server(SERVER_TYPE &server) {
// process GET request for /match/[digit+numbers], e.g.
// GET request is /match/abc123, will return abc123
server.resource["fill_your_reg_ex"]["GET"] = [](ostream& response, Request& request) {
// process GET request for /match/[digit+numbers],
// e.g. GET request is /match/abc123, will return abc123
server.resource["fill_your_reg_ex"]["GET"] =
[](ostream& response, Request& request)
{
string number=request.path_match[1];
response << "HTTP/1.1 200 OK\r\nContent-Length: " << number.length()
<< "\r\n\r\n" << number;
};
// peocess default GET request; anonymous function will be called if no other matches
// response files in folder web/
// peocess default GET request;
// anonymous function will be called
// if no other matches response files in folder web/
// default: index.html
server.default_resource["fill_your_reg_ex"]["GET"] =
[](ostream& response, Request& request) {
string filename = "www/";
string path = request.path_match[1];
// forbidden use `..` access content outside folder web/
size_t last_pos = path.rfind(".");
size_t current_pos = 0;
size_t pos;
while((pos=path.find('.', current_pos)) != string::npos && pos != last_pos) {
current_pos = pos;
path.erase(pos, 1);
last_pos--;
}
[](ostream& response, Request& request)
{
string filename = "www/";
string path = request.path_match[1];
// forbidden use `..` access content outside folder web/
size_t last_pos = path.rfind(".");
size_t current_pos = 0;
size_t pos;
while((pos=path.find('.', current_pos)) != string::npos && pos != last_pos) {
current_pos = pos;
path.erase(pos, 1);
last_pos--;
}
// (...)
};
Expand Down
18 changes: 11 additions & 7 deletions book/en-us/07-thread.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ int main() {
std::cout << "waiting...";
result.wait(); // block until future has arrived
// output result
std::cout << "done!" << std:: endl << "future result is " << result.get() << std::endl;
std::cout << "done!" << std:: endl << "future result is "
<< result.get() << std::endl;
return 0;
}
```
Expand Down Expand Up @@ -196,7 +197,8 @@ int main() {
// temporal unlock to allow producer produces more rather than
// let consumer hold the lock until its consumed.
lock.unlock();
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // consumer is slower
// consumer is slower
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
lock.lock();
if (!produced_nums.empty()) {
std::cout << "consuming " << produced_nums.front() << std::endl;
Expand Down Expand Up @@ -272,7 +274,7 @@ This is a very strong set of synchronization conditions, in other words when it
This seems too harsh for a variable that requires only atomic operations (no intermediate state).

The research on synchronization conditions has a very long history, and we will not go into details here. Readers should understand that under the modern CPU architecture, atomic operations at the CPU instruction level are provided.
Therefore, in the C++11 multi-threaded shared variable reading and writing, the introduction of the `std::atomic` template, so that we instantiate an atomic type, will be a
Therefore, in the C++11 multi-threaded shared variable reading and writing, the introduction of the `std::atomic` template, so that we instantiate an atomic type, will be an
Atomic type read and write operations are minimized from a set of instructions to a single CPU instruction. E.g:

```cpp
Expand Down Expand Up @@ -417,8 +419,11 @@ Weakening the synchronization conditions between processes, usually we will cons
```
3 4 4 4 // The write operation of x was quickly observed
0 3 3 4 // There is a delay in the observed time of the x write operation
0 0 0 4 // The last read read the final value of x, but the previous changes were not observed.
0 0 0 0 // The write operation of x is not observed in the current time period, but the situation that x is 4 can be observed at some point in the future.
0 0 0 4 // The last read read the final value of x,
// but the previous changes were not observed.
0 0 0 0 // The write operation of x is not observed in the current time period,
// but the situation that x is 4 can be observed
// at some point in the future.
```
### Memory Orders
Expand Down Expand Up @@ -480,9 +485,8 @@ To achieve the ultimate performance and achieve consistency of various strength
});
std::thread acqrel([&]() {
int expected = 1; // must before compare_exchange_strong
while(!flag.compare_exchange_strong(expected, 2, std::memory_order_acq_rel)) {
while(!flag.compare_exchange_strong(expected, 2, std::memory_order_acq_rel))
expected = 1; // must after compare_exchange_strong
}
// flag has changed to 2
});
std::thread acquire([&]() {
Expand Down
9 changes: 6 additions & 3 deletions book/zh-cn/02-usability.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ int main() {
}

// 将输出 1, 4, 3, 4
for (std::vector<int>::iterator element = vec.begin(); element != vec.end(); ++element)
for (std::vector<int>::iterator element = vec.begin(); element != vec.end();
++element)
std::cout << *element << std::endl;
}
```
Expand Down Expand Up @@ -228,7 +229,7 @@ int main() {
}
```

为了解决这个问题,C++11 首先把初始化列表的概念绑定到了类型上,并将其称之为 `std::initializer_list`,允许构造函数或其他函数像参数一样使用初始化列表,这就为类对象的初始化与普通数组和 POD 的初始化方法提供了统一的桥梁,例如:
为解决这个问题,C++11 首先把初始化列表的概念绑定到类型上,称其为 `std::initializer_list`,允许构造函数或其他函数像参数一样使用初始化列表,这就为类对象的初始化与普通数组和 POD 的初始化方法提供了统一的桥梁,例如:

```cpp
#include <initializer_list>
Expand All @@ -249,7 +250,9 @@ int main() {
MagicFoo magicFoo = {1, 2, 3, 4, 5};

std::cout << "magicFoo: ";
for (std::vector<int>::iterator it = magicFoo.vec.begin(); it != magicFoo.vec.end(); ++it) std::cout << *it << std::endl;
for (std::vector<int>::iterator it = magicFoo.vec.begin();
it != magicFoo.vec.end(); ++it)
std::cout << *it << std::endl;
}
```
Expand Down
7 changes: 4 additions & 3 deletions book/zh-cn/03-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ Lambda 表达式的本质是一个和函数对象类型相似的类类型(称
#include <iostream>
using foo = void(int); // 定义函数类型, using 的使用见上一节中的别名语法
void functional(foo f) { // 定义在参数列表中的函数类型 foo 被视为退化后的函数指针类型 foo*
void functional(foo f) { // 参数列表中定义的函数类型 foo 被视为退化后的函数指针类型 foo*
f(1); // 通过函数指针调用函数
}
Expand Down Expand Up @@ -193,7 +193,8 @@ int foo(int a, int b, int c) {
;
}
int main() {
// 将参数1,2绑定到函数 foo 上,但是使用 std::placeholders::_1 来对第一个参数进行占位
// 将参数1,2绑定到函数 foo 上,
// 但使用 std::placeholders::_1 来对第一个参数进行占位
auto bindFoo = std::bind(foo, std::placeholders::_1, 1,2);
// 这时调用 bindFoo 时,只需要提供第一个参数即可
bindFoo(1);
Expand Down Expand Up @@ -551,7 +552,7 @@ constexpr _Tp&& forward(typename std::remove_reference<_Tp>::type&& __t) noexcep
```
在这份实现中,`std::remove_reference` 的功能是消除类型中的引用,
`std::is_lvalue_reference` 用于检查类型推导是否正确,在 `std::forward` 的第二个实现中
`std::is_lvalue_reference` 则用于检查类型推导是否正确,在 `std::forward` 的第二个实现中
检查了接收到的值确实是一个左值,进而体现了坍缩规则。
当 `std::forward` 接受左值时,`_Tp` 被推导为左值,所以返回值为左值;而当其接受右值时,
Expand Down
20 changes: 11 additions & 9 deletions book/zh-cn/05-pointers.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ order: 5
也就是我们常说的 RAII 资源获取即初始化技术。

凡事都有例外,我们总会有需要将对象在自由存储上分配的需求,在传统 C++ 里我们只好使用 `new``delete`
『记得』对资源进行释放。而 C++11 引入智能指针的概念,使用引用计数的想法,让程序员不再需要关心手动释放内存。
这些智能指针就包括 `std::shared_ptr`/`std::unique_ptr`/`std::weak_ptr`,使用它们需要包含头文件 `<memory>`
『记得』对资源进行释放。而 C++11 引入了智能指针的概念,使用了引用计数的想法,让程序员不再需要关心手动释放内存。
这些智能指针包括 `std::shared_ptr`/`std::unique_ptr`/`std::weak_ptr`,使用它们需要包含头文件 `<memory>`

> 注意:引用计数不是垃圾回收,引用计数能够尽快收回不再被使用的对象,同时在回收的过程中也不会造成长时间的等待,
> 更能够清晰明确的表明资源的生命周期。
## 5.2 `std::shared_ptr`

`std::shared_ptr` 是一种智能指针,它能够记录多少个 `shared_ptr` 共同指向一个对象,从而消除显式的调用
`std::shared_ptr` 是一种智能指针,它能够记录多少个 `shared_ptr` 共同指向一个对象,从而消除显式的调用
`delete`,当引用计数变为零的时候就会将对象自动删除。

但还不够,因为使用 `std::shared_ptr` 仍然需要使用 `new` 来调用,这使得代码出现了某种程度上的不对称。
Expand Down Expand Up @@ -59,21 +59,23 @@ int main() {
auto pointer = std::make_shared<int>(10);
auto pointer2 = pointer; // 引用计数+1
auto pointer3 = pointer; // 引用计数+1
int *p = pointer.get(); // 这样不会增加引用计数
std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 3
int *p = pointer.get(); // 这样不会增加引用计数
std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 3
std::cout << "pointer2.use_count() = " << pointer2.use_count() << std::endl; // 3
std::cout << "pointer3.use_count() = " << pointer3.use_count() << std::endl; // 3
pointer2.reset();
std::cout << "reset pointer2:" << std::endl;
std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 2
std::cout << "pointer2.use_count() = " << pointer2.use_count() << std::endl; // 0, pointer2 已 reset
std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 2
std::cout << "pointer2.use_count() = "
<< pointer2.use_count() << std::endl; // pointer2 已 reset; 0
std::cout << "pointer3.use_count() = " << pointer3.use_count() << std::endl; // 2
pointer3.reset();
std::cout << "reset pointer3:" << std::endl;
std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 1
std::cout << "pointer.use_count() = " << pointer.use_count() << std::endl; // 1
std::cout << "pointer2.use_count() = " << pointer2.use_count() << std::endl; // 0
std::cout << "pointer3.use_count() = " << pointer3.use_count() << std::endl; // 0, pointer3 已 reset
std::cout << "pointer3.use_count() = "
<< pointer3.use_count() << std::endl; // pointer3 已 reset; 0
```

## 5.3 `std::unique_ptr`
Expand Down
24 changes: 16 additions & 8 deletions book/zh-cn/06-regex.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ C++11 提供的正则表达式库操作 `std::string` 对象,

int main() {
std::string fnames[] = {"foo.txt", "bar.txt", "test", "a0.txt", "AAA.txt"};
// 在 C++ 中 \ 会被作为字符串内的转义符,为使 \. 作为正则表达式传递进去生效,需要对 \ 进行二次转义,从而有 \\.
// 在 C++ 中 \ 会被作为字符串内的转义符,
// 为使 \. 作为正则表达式传递进去生效,需要对 \ 进行二次转义,从而有 \\.
std::regex txt_regex("[a-z]+\\.txt");
for (const auto &fname: fnames)
std::cout << fname << ": " << std::regex_match(fname, txt_regex) << std::endl;
Expand All @@ -103,7 +104,7 @@ int main() {

另一种常用的形式就是依次传入 `std::string`/`std::smatch`/`std::regex` 三个参数,
其中 `std::smatch` 的本质其实是 `std::match_results`
在标准库中`std::smatch` 被定义为了 `std::match_results<std::string::const_iterator>`
故而在标准库的实现中`std::smatch` 被定义为了 `std::match_results<std::string::const_iterator>`
也就是一个子串迭代器类型的 `match_results`
使用 `std::smatch` 可以方便的对匹配的结果进行获取,例如:

Expand Down Expand Up @@ -193,16 +194,23 @@ protected:
template<typename SERVER_TYPE>
void start_server(SERVER_TYPE &server) {
// process GET request for /match/[digit+numbers], e.g. GET request is /match/abc123, will return abc123
server.resource["fill_your_reg_ex"]["GET"] = [](ostream& response, Request& request) {
// process GET request for /match/[digit+numbers],
// e.g. GET request is /match/abc123, will return abc123
server.resource["fill_your_reg_ex"]["GET"] =
[](ostream& response, Request& request)
{
string number=request.path_match[1];
response << "HTTP/1.1 200 OK\r\nContent-Length: " << number.length() << "\r\n\r\n" << number;
response << "HTTP/1.1 200 OK\r\nContent-Length: "
<< number.length() << "\r\n\r\n" << number;
};
// peocess default GET request; anonymous function will be called if no other matches
// response files in folder web/
// peocess default GET request;
// anonymous function will be called
// if no other matches response files in folder web/
// default: index.html
server.default_resource["fill_your_reg_ex"]["GET"] = [](ostream& response, Request& request) {
server.default_resource["fill_your_reg_ex"]["GET"] =
[](ostream& response, Request& request)
{
string filename = "www/";
string path = request.path_match[1];
Expand Down
Loading

0 comments on commit e50e3c6

Please sign in to comment.