Tổng quan và triết lý của STL
Thuộc phần Lập trình hướng đối tượng trong hành trình C++ của Coddy. Bài học 70 trên 104.
Standard Template Library (STL) là một tập hợp các lớp và hàm dựa trên template, cung cấp các cấu trúc dữ liệu và thuật toán phổ biến. Được xây dựng dựa trên các khái niệm template bạn đã học, STL thể hiện một triết lý thiết kế mạnh mẽ: tách biệt việc lưu trữ dữ liệu với việc thao tác dữ liệu.
STL được tổ chức quanh ba thành phần cốt lõi hoạt động cùng nhau:
| Thành phần | Mục đích | Ví dụ |
|---|---|---|
| Bộ chứa | Lưu trữ tập hợp các đối tượng | vector, map, set |
| Bộ lặp | Cung cấp quyền truy cập vào các phần tử trong bộ chứa | Đầu vào, đầu ra, truy cập ngẫu nhiên |
| Thuật toán | Thực hiện các thao tác trên dữ liệu | sort, find, transform |
Điều cốt lõi là thuật toán không trực tiếp biết về các vùng chứa, chúng hoạt động thông qua trình lặp. Điều này có nghĩa là một thuật toán sort duy nhất hoạt động với vector, mảng và mọi vùng chứa cung cấp đúng kiểu trình lặp:
#include <vector>
#include <algorithm>
#include <iostream>
int main() {
std::vector<int> nums = {5, 2, 8, 1, 9};
std::sort(nums.begin(), nums.end());
for (int n : nums) {
std::cout << n << " ";
}
// Đầu ra: 1 2 5 8 9
}Cách tách biệt này cho phép bạn kết hợp linh hoạt: dùng bất kỳ thuật toán nào với bất kỳ vùng chứa tương thích nào mà không cần viết code mới. STL cung cấp các phần triển khai đã được kiểm chứng kỹ lưỡng và tối ưu hóa, để bạn tập trung giải quyết vấn đề thay vì tạo lại các cấu trúc dữ liệu phổ biến.
Thử thách
DễHãy xây dựng một hệ thống xử lý dữ liệu đơn giản để minh họa triết lý của STL về việc tách biệt thùng chứa (container), bộ lặp (iterator) và thuật toán. Bạn sẽ tạo một module tiện ích hoạt động với các thành phần STL và một chương trình chính cho thấy những phần này kết hợp với nhau như thế nào.
Bạn sẽ tạo hai tệp:
DataProcessor.h: Định nghĩa các hàm tiện ích hoạt động với thùng chứa STL thông qua bộ lặp, qua đó minh họa triết lý thiết kế của STL.Tạo một hàm có tên
printVector, nhận mộtstd::vector<int>&và in tất cả phần tử, cách nhau bằng dấu cách, rồi xuống dòng. Dùng bộ lặp (begin()vàend()) để duyệt thùng chứa.Tạo một hàm có tên
sortAndPrint, nhận mộtstd::vector<int>&, sắp xếp vector bằngstd::sort, rồi in các phần tử đã sắp xếp, cách nhau bằng dấu cách, sau đó xuống dòng.Tạo một hàm có tên
findElement, nhận mộtstd::vector<int>&và một giá trịintcần tìm. Dùngstd::findđể tìm phần tử đó. Nếu tìm thấy, inFound: <value>. Nếu không tìm thấy, inNot found: <value>.Tạo một hàm có tên
getSum, nhận mộtstd::vector<int>&và trả về tổng của tất cả phần tử. Bạn có thể dùng một vòng lặp đơn giản với bộ lặp để tính tổng.main.cpp: Đọc dữ liệu đầu vào và minh họa cách các thành phần STL hoạt động cùng nhau.Đọc năm giá trị đầu vào, mỗi giá trị trên một dòng riêng:
- Số nguyên thứ nhất
- Số nguyên thứ hai
- Số nguyên thứ ba
- Số nguyên thứ tư
- Giá trị cần tìm
Tạo một
std::vector<int>và thêm bốn số nguyên đầu tiên vào đó. Sau đó, minh họa triết lý của STL bằng cách:- In
Original:, rồi gọiprintVector - In
Sorted:, rồi gọisortAndPrint - Gọi
findElementvới giá trị cần tìm - In
Sum: <result>bằnggetSum
Ví dụ, với các giá trị đầu vào 5, 2, 8, 1 và 8:
Original: 5 2 8 1
Sorted: 1 2 5 8
Found: 8
Sum: 16Với các giá trị đầu vào 10, 30, 20, 40 và 15:
Original: 10 30 20 40
Sorted: 10 20 30 40
Not found: 15
Sum: 100Hãy chú ý cách các hàm của bạn thao tác với vector thông qua bộ lặp, cũng như cách std::sort và std::find hoạt động trên bất kỳ thùng chứa nào cung cấp đúng kiểu bộ lặp. Đây chính là sức mạnh trong thiết kế của STL: các thuật toán được tách biệt khỏi thùng chứa và chỉ kết nối với chúng thông qua bộ lặp.
Tự làm thử
#include <iostream>
#include <vector>
#include "DataProcessor.h"
using namespace std;
int main() {
// Đọc năm số nguyên từ đầu vào
int num1, num2, num3, num4, searchValue;
cin >> num1;
cin >> num2;
cin >> num3;
cin >> num4;
cin >> searchValue;
// TODO: Tạo một vector và thêm bốn số nguyên đầu tiên vào đó
// TODO: In ra "Original: " rồi gọi printVector
// TODO: In ra "Sorted: " rồi gọi sortAndPrint
// TODO: Gọi findElement với giá trị cần tìm
// TODO: In ra "Sum: " rồi đến kết quả của getSum
return 0;
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về OOP
Tệp bên ngoàiBiên dịch và tạo bản dựng C++Tệp header và tệp nguồnNamespace và phạm viGiới thiệu về OOP trong C++Lớp và đối tượngCon trỏ thisPhương thức (hàm thành viên)Thuộc tính (dữ liệu thành viên)Cơ bản về hàm khởi tạo và hàm hủyÔn tập: máy tính đơn giản4Thuộc tính của lớp
Thành viên đối tượng và thành viên tĩnhHàm truy xuất và hàm thiết lậpHàm thành viên hằngTừ khóa mutablePhương thức và biến tĩnhHàm và lớp bạnÔn tập: Trình quản lý tài khoản ngân hàng7Kế thừa
Kế thừa cơ bảnMức truy cập trong kế thừaThứ tự gọi hàm khởi tạo và hàm hủyGhi đè phương thứcHàm ảo và VTableĐa kế thừaKế thừa ảoÔn tập: hệ phân cấp nhân viên10Tổng quan về STL
Tổng quan và triết lý của STLCác vùng chứa của STLBộ lặpCác thuật toán của STLHàm tử và biểu thức lambdaÔn tập: tần suất từ2Quản lý bộ nhớ
Bộ nhớ ngăn xếp và heapCon trỏ và tham chiếuBộ nhớ động (new/delete)Con trỏ thông minh trong C++RAII trong C++Ôn tập: Trình quản lý mảng động5Tính đóng gói
Phạm vi truy cập trong C++Tìm hiểu sâu về phạm vi truy cậpẨn thông tinStruct và lớpLớp lồng nhau và lớp bên trongÔn tập: hệ thống hồ sơ sinh viên8Đa hình
Đa hình lúc biên dịch và khi chạyNạp chồng hàmÔn lại hàm ảoHàm ảo thuần túyLớp trừu tượngThiết kế interface trong C++Ép kiểu động và RTTIÔn tập: Máy tính hình học3Hàm khởi tạo và hàm hủy
Hàm khởi tạo mặc địnhHàm khởi tạo có tham sốHàm khởi tạo sao chépHàm khởi tạo di chuyểnDanh sách khởi tạoHàm khởi tạo ủy quyềnTìm hiểu sâu về hàm hủyQuy tắc 3 / 5 / 0Ôn tập: lớp chuỗi6Nạp chồng toán tử
Giới thiệu về nạp chồng toán tửNạp chồng toán tử số họcNạp chồng toán tử so sánhToán tử luồngNạp chồng toán tử gánNạp chồng toán tử [] và ()Toán tử chuyển đổi kiểuÔn tập: lớp ma trận9Mẫu
Mẫu hàmMẫu lớpChuyên biệt hóa mẫuMẫu biến tham sốCơ bản về SFINAE và đặc điểm kiểuÔn tập: vùng chứa tổng quátTự luyện tập: Trình biên dịch C++ online