Bài giảng Kỹ thuật lập trình - Bài 13: C++11 - Đào Trung Kiên

pdf 23 trang ngocly 4470
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Kỹ thuật lập trình - Bài 13: C++11 - Đào Trung Kiên", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfbai_giang_ky_thuat_lap_trinh_bai_13_c11_dao_trung_kien.pdf

Nội dung text: Bài giảng Kỹ thuật lập trình - Bài 13: C++11 - Đào Trung Kiên

  1. Bài 13: C++11 1 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  2. Các phiên bản C++  C++98 (đã học trong các bài trước):  Được ISO chuẩn hoá lần đầu tiên  C++03:  Một số thay đổi nhỏ  C++0x / C++11:  Rất nhiều cập nhật mới  Nhiều tính năng được lấy lại từ thư viện boost  C++14:  Một số mở rộng so với C++11  C++17:  Đang thảo luận 2 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  3. Tự suy đoán kiểu  Ví dụ: map > m; // map >::iterator itr = m.begin(); auto itr = m.begin(); // pair & a = m["KTLT"]; auto& a = m["KTLT"]; // pair b; decltype(a) b; 3 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  4. Vòng lặp for theo khoảng (range-based for loop) double a[10]; list l; vector v; for (int x : a) { // } for (string& x : l) { // } for (complex& x : v) { // } 4 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  5. Con trỏ thông minh (smart pointers)  Là kiểu trừu tượng cho phép mô phỏng các con trỏ, nhưng bổ sung thêm một số tính năng khác:  Quản lý bộ nhớ tự động  Kiểm tra phạm vi  Ví dụ: shared_ptr p1(new int(10)); shared_ptr p2 = p1; *p2 = 20; // bộ nhớ sẽ được thu hồi khi // tham chiếu cuối cùng được huỷ 5 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  6. Đa luồng (multithreading) & Lập trình song song (concurrency) 6 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  7. Luồng (threads)  Cho phép thực thi các nhiệm vụ đồng thời (song song, không đồng bộ), chú ý phân biệt luồng và tiến trình (process)  Luôn có ít nhất một luồng trong chương trình, được tạo cho hàm main: được gọi là luồng chính  Trước C++11, các luồng được quản lý bởi các thư viện ngoài:  POSIX thread (pthread)  Windows API  OpenMP  MPI  Từ C++11, đa luồng là một tính năng có sẵn  #include  Lớp std::thread  Mỗi luồng được thực thi trong một hàm gọi là thread function 7 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  8. Ví dụ #include void task2() { #include for (int i = 0; i i++) { this_thread::sleep_for( chrono::milliseconds(100)); using namespace std; cout << "Thread 2\n"; } void task1() { } for (int i = 0; i < 100; i++) { this_thread::sleep_for( void main() { chrono::milliseconds(100)); thread t(task1); cout << "Thread 1\n"; task2(); } t.join(); } } 8 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  9. Luồng với tham số #include void main() { #include thread a[10]; int i, n = 0; #include using namespace std; for (i=0; i<10; i++) a[i] = thread( void task(int* n) { task, &n); int i, t; for (i=0; i<10; i++) for (i=0; i<100; i++) { a[i].join(); t = *n; this_thread::sleep_for( cout << n << endl; chrono::milliseconds(1)); } *n = t + 1; } } 9 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  10. Critical sections & quản lý sử dụng tài nguyên  Các luồng trong cùng một process chia sẻ bộ nhớ  Một luồng có thể sử dụng bộ nhớ được cấp phát từ các luồng khác  Việc cập nhật các biến chung từ các luồng khác nhau có thể dẫn đến kết quả không mong muốn Luồng 1 Luồng 2 Giá trị  Việc sử dụng tài i = 10 nguyên phải được t = i; t#1 = 10 quản lý t = i; t#2 = 10 t ++; t#1 = 11 Critical sections t ++; t#2 = 11  Các tài nguyên có i = t; i = 11 thể được hiểu theo i = t; i = 11 nghĩa rộng 10 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  11. Lớp mutex  Mutex = mutual exclusion (loại trừ lẫn nhau) không quá 1 luồng thực thi đoạn mã ở một thời điểm #include mutex m; void task(int* n) { int i, t; for (i=0; i<100; i++) { m.lock(); t = *n; critical this_thread::sleep_for(chrono::milliseconds(1)); section *n = t + 1; m.unlock(); } } 11 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  12. Lớp parallel_for  Duyệt các phần tử và thực thi một hàm cho trước một cách song song (tối ưu theo số CPU của máy) #include void task(int itr) { #include for (int i=0; i int t = n; #include this_thread::sleep_for( #include chrono::milliseconds(1)); n = t + 1; m.unlock(); using namespace std; } using namespace } concurrency; void main() { int n = 0; parallel_for(0, 10, task); cout << n << endl; mutex m; } 12 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  13. Hàm lambda 13 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  14. Khái niệm  Còn gọi là hàm không tên, được định nghĩa trong các câu lệnh  Thường được dùng như tham số khi gọi các hàm khác  Có thể được chuyển kiểu thành hàm thông thường khi không có “capture” nào  Cú pháp: [các-capture](các-tham-số) -> kiểu-trả-về { thực-thi }  các-capture: danh sách các biến thuộc phạm vi định nghĩa được sử dụng trong hàm, phân cách bằng dấu “,”. Ví dụ:  [a, &b, c, &d]: a và c bằng giá trị, b và d bằng tham chiếu  [&, a, b]: a và b bằng giá trị, còn lại bằng tham chiếu  [=, &a, &b]: a và b bằng tham chiếu, còn lại bằng giá trị  kiểu-trả-về: có thể bỏ qua nếu suy luận được 14 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  15. Ví dụ 1 const int n = 10; int x[n] = { }; std::sort(x, x + n, [](int a, int b) { return abs(a) < abs(b); } );  Viết theo C++98: bool compare(int a, int b) { return abs(a) < abs(b); } std::sort(x, x + n, compare); 15 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  16. Ví dụ 2 int func(int a, function lambda) { return lambda(a); } void main() { int n = 10, m = 20; int p = func(n, [m](int i) { return i*m; }); cout << p << endl; } 16 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  17. parallel_for void main() { int n = 0; mutex m; parallel_for(0, 10, [&m, &n](int itr) { for (int i = 0; i < 100; i++) { m.lock(); int t = n; this_thread::sleep_for(chrono::milliseconds(1)); n = t + 1; m.unlock(); } }); cout << n << endl; } 17 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  18. Tham chiếu rvalue & Ý nghĩa move 18 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  19. Lvalue và rvalue  Mỗi biểu thức C++ là một lvalue hoặc rvalue  Lvalues: các giá trị có thể tham chiếu (những gì có thể lưu giá trị, có thể được đặt ở vế trái của câu lệnh gán)  Rvalues: các giá trị tạm thời không tồn tại sau khi biểu thức dùng nó kết thúc (chỉ được đặt ở vế phải của câu lệnh gán)  Ví dụ:  int i = 100;  const int a = x * y;  int& m = i; 19 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  20. Ý nghĩa move  Xem constructor sao chép của lớp string: string& operator =(const string& str) { // }  Ví dụ sử dụng: s = "abc"; 1. Giải phóng các tài nguyên s sử dụng 2. Sao chép tài nguyên từ đối tượng tạm thời 3. Giải phóng đối tượng tạm, và do đó, giải phóng các tài nguyên nó sử dụng Không tối ưu về hiệu năng hoạt động! Tại sao không chuyển đổi (move) tài nguyên của các đối tượng cho nhau? 20 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  21. Tham chiếu rvalue  Tham chiếu rvalue (string&&) là các tham chiếu tới rvalue, được dùng trong quá trình move  s = "abc";  s = s1 + s2;  string ss(s1 + s2);  “Tham chiếu truyền thống” (string&) nay được gọi là tham chiếu lvalue, được sử dụng trong quá trình copy  s = s1;  string ss(s1);  Ta cần phải định nghĩa thêm:  1 toán tử gán move (bên cạnh toán tử gán copy)  1 constructor move (bên cạnh constructor copy) 21 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  22. Các constructor copy và move class string { protected: char* p; public: string(const string& s) { // (as before) } string(const string&& s) { p = s.p; } }; 22 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội
  23. Các toán tử gán copy và move class string { protected: char* p; public: string& operator =(const string& s) { // (as before) } string& operator =(const string&& s) { p = s.p; return *this; } }; 23 EE3490: Kỹ thuật lập trình – HK1 2017/2018 TS. Đào Trung Kiên – ĐH Bách khoa Hà Nội