Chuẩn C++11 – Như một ngôn ngữ lập trình mới

| - Chuyên mục: Truyền thông số
Là một trong những ngôn ngữ lập trình phổ biến nhất trên thế giới (cùng với C, Objective-C, và Java [1]), C++ được Stroustrup tạo ra vào đầu những năm 1980. Đến năm 1998 C++ đã trở thành một chuẩn (standard) được công nhận, chuẩn này thường được gọi là C++98, qui ước đặt tên chuẩn gắn liền với năm cũng bắt đầu từ đây.

Năm 2005, ủy ban tiêu chuẩn của ISO (với các thành viên là Stroustrup và các lập trình viên C++ hàng đầu trên thế giới [2]) đã thông qua chuẩn C++0x và tới năm 2011, chuẩn C++11 đã chính thức được ban hành với khá nhiều thay đổi quan trọng. Chuẩn tiếp theo của C++ dự kiến sẽ được thông qua vào năm 2014 và sẽ có tên là C++14. Trong bài viết này, nhằm mang lại cho các bạn độc giả một cái nhìn tổng quan, tôi sẽ trình bày về các khía cạnh nổi bật nhất, cùng với một số sách, phần mềm cần thiết để có thể học, hiểu và lập trình theo chuẩn C++11.

Đầu tiên cần phải hiểu rõ mục đích của việc xây dựng các chuẩn mới (C++11, C++14) vì bản thân C++98 (với các khái niệm vẫn đang được phổ biến trong các khóa dạy về lập trình C++, lập trình hướng đối tượng trong các trường đại học và vẫn được các lập trình viên C++ dùng để viết các phần mềm) hoặc C++0x đã ổn định và khá hiệu quả, vậy tại sao lại cần thêm các chuẩn này? Có phải chỉ để đưa vào các khái niệm mới, trừu tượng hơn và chỉ phục vụ cho việc phát triển các thư viện (như STL) hay không? Mục đích của việc đưa ra các chuẩn C++ mới, thể hiện rõ nhất với C++11 (vì C++0x không có nhiều thay đổi lớn so với C++98) là nhằm:

+ Đạt được hiệu năng cao hơn (tốc độ, sử dụng bộ nhớ, tận dụng các cấu trúc phần cứng mới-các bộ xử lý đa nhân ...) với các chương trình viết bằng C++.

+ Hiệu quả lập trình cao hơn qua việc cung cấp các lớp, cú pháp và kỹ thuật lập trình mới nhằm đẩy mạnh xu hướng lập trình generic.
+ Có sự tương thích với các phiên bản C++ cũ (C++98, C++0x).
+ Không đưa thêm vào quá nhiều các khái niệm mới hoặc các tính năng chưa ổn định.
+ Có thể xem chi tiết hơn ở [3].

Trên thực tế có nhiều thứ được đưa vào chuẩn C++11 là đã có và đang được sử dụng rộng rãi như smart pointers, lambda, thread, chrono ... đa số trong số này nằm trong boost [4], một tập các thư viện C++ rất hữu dụng, vì thế những ai đã quen với boost sẽ cảm thấy rất thuận tiện với chuẩn C++11.

Vậy làm thế nào có thể học lập trình C++ theo chuẩn C++11? Đầu tiên là tài liệu, hiện nay có các tài liệu sau:

1. The C++ language, 4th edition, 2013, quyển sách này được viết bởi chính Stroustrup, rất đầy đủ và cập nhật nhưng chủ yếu có tác dụng tra cứu chứ không giúp ích nhiều cho việc triển khai công việc thực tế.

2. Professional C++ 2nd Edition, 2011, một cuốn sách cập nhật (so với C++11) và được đánh giá khá cao.

3. Data Structures and Algorithm Analysis in C++, 4th edition, 2014, một cuốn sách rất mới và hay, viết về cấu trúc dữ liệu và giải thuật với C++ của giáo sư Mark Allen Weiss, Florida International University, cập nhật chuẩn C++11.

4. The C++ Standard Library, 2nd edition, 2012. Một cuốn chuyên lập trình C++ theo chuẩn C++11 với phần lớn nội dung dành cho thư viện STL. Các bạn đang học cấu trúc dữ liệu hoặc STL có thể đọc quyển này và cuốn số 3

5. C++ Concurrency in Action, 2012, của Anthony Williams, cho tới hiện nay, vẫn là cuốn duy nhất viết về lập trình đa luồng (multithread) đầy đủ nhất với C++11. Cuốn này dành riêng cho chủ đề đa luồng, tương tranh.

Tiếp đến là phần mềm, cần phân biệt hai loại, compiler và editor. Về compiler phổ biến nhất là G++ (GNU C++) thuộc GCC, MS VC (Microsoft Visual C++ compiler) thuộc bộ phần mềm phát triển tích hợp Visual Studio của MS. Ngoài ra còn có bộ biên dịch Clang cho Mac OS, bộ compiler của Intel ... Trong khi G++ (từ bản 4.8.1 được phát hành tháng 5-2013) đã cài đặt đầy đủ các tính năng mới của chuẩn C++11 thì MS VC (dù là bản 2013) vẫn còn nhiều tính năng chưa được hỗ trợ (chẳng hạn như constexpr hay list-initialization, có thể là do các developper của MS cho rằng các tính năng đó chưa quan trọng lắm...). Tiếp đến là editor, nếu chọn bộ VS thì không cần lo vấn đề này vì VS nổi tiếng về sự tiện lợi (tất nhiên vẫn có những chỗ hơi bất tiện, nhưng là số ít), ngược lại có thể dùng Orwell DevCpp (được phát triển tiếp từ DevCpp của hãng BloodShed), rất thích hợp cho việc dùng với gcc và môi trường giáo dục, dành cho những ai mới bắt đầu hoặc đơn giản là cấu hình máy tính không thích hợp cho việc cài VS và các phần mềm khác, vì bộ này (cùng với GCC) không cần cài đặt và yêu cầu cấu hình thấp, dung lượng nhỏ. Code::Block là một IDE có nhiều tính năng tiện lợi hơn DevCpp và cũng miễn phí, tiếp đến là Qt Creator, cũng miễn phí và dễ dùng. Mạnh nhất (trong số các phần mềm miễn phí, và cũng khó dùng hơn) là Eclipse. Vì bộ compiler của MS VS không hỗ trợ đầy đủ nên theo tôi nếu có thể thì nên dùng bản VS 2012 Update 4 (đối với các hệ thống cũ 32 bit, chip Core 2 Duo, 4GB Ram) hoặc VS 2013 Update 1 cho cập nhật.

Sau đây là các đặc điểm nổi bật nhất của chuẩn C++11.

1. Khởi tạo theo kiểu danh sách (List initialization)
Tính năng này cho phép chúng ta có thể khai báo và khởi tạo các giá trị ban đầu cho một đối tượng thuộc một lớp chứa nào đó một cách linh hoạt theo cú pháp sau:
object = {arg1, arg2, …, argn};
Ví dụ:
vectorvi = {2, 8, 0, 3};
vectorvs = {“abc”, “xyz”};
Thực chất thì tính năng này C++ học tập từ C (khai báo và khởi tạo mảng) và bắt đầu đưa vào từ chuẩn C++0x, đến C++11 thì hoàn thiện với việc đưa vào lớp bản mẫu std::initializer_listđược gọi tới một cách tự động bởi trình biên dịch qua cú pháp {}.

2. Các hàm lambda (còn gọi là lambda expressions)
Xuất phát từ các lớp toán tử hàm (Functor classes), là các lớp cài đặt toán tử gọi hàm operator(), thường được dùng như các vị từ (predicate) cho các thuật toán của thư viện bản mẫu chuẩn STL, lambda được đưa vào chuẩn C++11 để giảm bớt công việc của các lập trình viên mà vẫn đạt được hiệu năng cao. Điều này xuất phát từ thực tế là mỗi khi cần sử dụng một vị từ, một lập trình viên cần phải viết code cho cả lớp toán tử hàm đó (cấu tử, khai báo các thành viên dữ liệu, và toán tử gọi hàm, tất nhiên) nên thường họ có xu hướng viết hẳn một vòng lặp thay vì gọi một vị từ, kết quả là việc tối ưu mã nguồn của trình biên dịch không được thực hiện, đồng nghĩa với hiệu năng chương trình không được cải thiện. Lambda đóng vai trò như một hàm không tên (anonymous/unnamed function) và trình biên dịch sẽ thay thế chúng bằng một con trỏ hàm khi dịch chương trình. Hãy xem ví dụ sau khi chúng ta cần gọi hàm sort() để sắp xếp một mảng số thực lưu trong một vector: