mirror of
https://github.com/changkun/modern-cpp-tutorial.git
synced 2025-12-17 04:34:40 +03:00
book: formatting style updates (#231)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
```
|
||||
@@ -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;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -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);
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -57,27 +57,27 @@ 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`
|
||||
@@ -85,7 +85,7 @@ std::cout << "pointer3.use_count() = "
|
||||
`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
|
||||
```
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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/";
|
||||
[](ostream& response, Request& request)
|
||||
{
|
||||
string filename = "www/";
|
||||
|
||||
string path = request.path_match[1];
|
||||
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--;
|
||||
}
|
||||
// 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--;
|
||||
}
|
||||
|
||||
// (...)
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
```
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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([&]() {
|
||||
|
||||
Reference in New Issue
Block a user