Smart Pointer
- Thông thường khi ta dùng đến pointer, giả sử như pointer của class
Employee
đi, ta sẽ tạo như sau:
- Khi tạo pointer, C++ sẽ tự động tìm phần memory trống trên bộ nhớ Heap để tạo
Employee* ptr
và sau đó trả về địa chỉ, ta cứ dùng địa chỉ ấy, hoặc không có thể dùng thẳngEmployee
bằng cách gọi&ptr
(cái này còn có thuật ngữ là dereference, đơn giản là truy cập giá trị mà pointer đang trỏ tới). - Thế nhưng, khi C++ tạo
Employee* ptr
trên Heap thì nó sẽ không tự động xoá (khác với tạo trên Stack), do đó nếu không viếtdelete ptr
thì sẽ có 2 vấn đề, bị lãng phí bộ nhớ. - Hiểu được như thế, từ C++11 ta có thứ mới gọi là Smart Pointer, dễ hiểu nhất thì là pointer tự động xoá còn sao để tự động xoá thì khá phức tạp đấy.
- Smart pointer trong C++ gồm 2 loại là
std::unique_ptr
vàstd::shared_ptr
. Để hiểu rõ khác nhau thì trước tiên có 2 term mà ta cần để ý là Ownership và Resource. Đầu tiên thì Resource là phần mà pointer đang trỏ đến và Ownership nói đến có bao nhiêu "người" đang sở hữu Resource ấy (hay có bao nhiêu pointer đang trỏ đến). - Dựa theo tên thì
std::unique_ptr
chỉ có duy nhất 1 owner cho 1 resource cònstd::shared_ptr
thì nhiều owner cho 1 resource.
Using
- Nếu các bạn đã từng code C thì đã biết về
#define
, một cách để các bạn có thể tạo tên khác cho kiểu dữ liệu, ví dụ như này nhé (mình lấy ví dụ từ 1):
- Thế nhưng ở C++, chúng ta có cách khác là dùng
using
, nhưng sẽ có một vài khác biệt và đối với mình, nếu đã dùng C++ thì nên bỏ những cái của C 🐧.
- Ngoài ra using còn giúp code gõ gọn hơn khá nhiều, ví dụ như dưới đây:
Uniform Initilization
- Ở C++11 ta có thêm một thứ gọi là Uniform Initilization (mình sẽ gọi tắt UI), nó như này:
- Một trong những thứ đầu tiên UI làm được là tránh đi "tính năng" Narrowing của C++. Narrowing đơn giản là bạn chuyển từ
float
sangint
hay ngược lại (ngoài ra còn nhiều trường hợp nữa, tham khảo ở đây 2).
- Ngoài ra nhờ UI mà khi khởi tạo các
Struct, std::vector, ...
sẽ dễ thở hơn, ví dụ như:
Conditional Statement
Bạn có biết từ C++17 mình có thể tạo biến (hay gọi là Initializers) trong điều kiện if-else
hay switch
tương tự như vòng for
. Ví dụ:
- Ngoài ra ở C++20, có một tính năng mới cực thú vị gọi là
Spaceship Operator
nó như thế này<=>
(bởi vì nó giống như phi thuyền nên gọi là spaceship). Khác với<, <=, >=, ==, >
trả vềbool
thì spaceship trả về kiểu dữ liệu riêng của nó gọi làstrong_ordering
hoặcpartial_ordering
nhưng nó khá rắc rối nên người ta dùng luônauto
. Và kiểu dữ liệu này có thể dùng so sánh như sau:
Attributes
Từ C++17, ta có cái gọi là Attributes, cái này đơn giản là chỉ dẫn cho Compiler nên làm gì. Ví dụ như ta có vòng swtich như này:
Có thể thấy ở ví dụ trên, khi không có break
ở case Grade::Good
thì C++ sẽ tự động chạy tiếp case Grade::Excellent
, và Compiler sẽ tạo Warning không nên dùng như vậy, nhưng nếu là chủ ý của mình, thì ta có thể thêm Attributes [[fallthrough]]
để cho C++ biết rằng đây là chủ ý:
Ngoài ra còn nhiều Attributes khác, ví dụ như:
- Giả sử ta có 1 hàm và hàm đó có return value, ta có thể dùng
[[nodiscard]]
để thông báo nếu người dùng không sử dụng return value ấy, ví dụ như:
- Giả sử ta có một hàm có tham số nhưng không dùng đến tham số đó, ví dụ như đạo hàm của hàm Linear, ta có thể dùng
[[maybe_unused]]
như sau:
- Ví dụ như có một hàm mà khi chạy hàm đó, chắc chắn chương trình sẽ dừng (không return), ví dụ như hàm tắt chương trình khi bị lỗi, ta có thể dùng
[[noreturn]]
:
- Ngoài ra còn rất nhiều attribute khác nữa, có thể tham khảo thêm ở https://en.cppreference.com/w/cpp/language/attributes.
Trailing return
- Đây là một syntax mới ở C++11 được dùng để viết kiểu trả về (return type) của một hàm, ví dụ như dưới đây:
- Đối với trả về là
int
thì bạn thấy nó không có gì mới mấy nhưng mà với những kiểu trả về lạ và dài hơn ví dụ như này: