Trong bài này, bạn sẽ được học về các lớp lưu trữ khác nhau trong C++. Bao gồm: local(cục bộ), global(toàn cục), static local(static cục bộ), register(thanh ghi) và thread local(cục bộ luồng).
Mỗi biến trong C++ có hai đặc trưng: kiểu và lớp lưu trữ.
Kiểu chỉ ra dạng dữ liệu sẽ được lưu trong một biến. Ví dụ: int, float, char…
Và lớp dữ liệu điều khiển hai đặc tính khác của một biến: thời gian tồn tại (quyết định một biến có thể tồn tại trong bao lâu) và phạm vi (quyết định phần nào của chương trình có thể truy cập).
Tùy theo lớp lưu trữ của một biến, nó có thể được phân thành 4 kiểu chính:
- Biến cục bộ (Local variable)
- Biến toàn cục (Global variable)
- Biến cục bộ static (Static local variable)
- Biến thanh ghi (Register variable)
- Lưu trữ cục bộ trên luồng (Thread local storage)
Biến cục bộ
Một biến được định nghĩa bên trong một hàm (định nghĩa trong thân hàm, giữa hai dấu ngoặc nhọn) được gọi là biến cục bộ hoặc biến tự động.
Phạm vi của nó chỉ giới hạn cho hàm mà nó được định nghĩa. Nói cách khác, biến cục bộ chỉ tồn tại và truy cập được bên trong một hàm.
Thời gian tồn tại của biến cục bộ kết thúc (bị hủy) khi hàm kết thúc.
Ví dụ 1: biến cục bộ
#include <iostream>
using namespace std;
void test();
int main()
{
// biến cục bộ của hàm main()
int var = 5;
test();
// không hợp lệ: var1 không được định nghĩa trong main()
var1 = 9;
}
void test()
{
// biến cục bộ của hàm test()
int var1;
var1 = 6;
// không hợp lệ: var không được định nghĩa trong test()
cout << var;
}
Biến var không thể được sử dụng trong hàm test() và var1 không thể sử dụng trong hàm main().
Từ khóa auto cũng có thể được sử dụng để định nghĩa biến cục bộ: auto int var;
Nhưng từ sau C++11, auto có ý nghĩa khác và không nên sử dụng để định nghĩa biến cục bộ.
Biến toàn cục
Nếu một biến được định nghĩa ngoài tất cả các hàm, nó sẽ được gọi là biến toàn cục.
Phạm vi của biến toàn cục là toàn bộ chương trình. Nghĩa là nó có thể được sử dụng và thay đổi tại bất kỳ phần nào của chương trình sau khi đã được khai báo.
Thêm vào đó, thời gian tồn tại của nó chỉ kết thúc khi chương trình dừng.
Ví dụ 2: Biến toàn cục
#include <iostream>
using namespace std;
// Khai báo biến toàn cục
int c = 12;
void test();
int main()
{
++c;
// đầu ra là 13
cout << c <<endl;
test();
return 0;
}
void test()
{
++c;
// đầu ra là 14
cout << c;
}
Đầu ra
13
14 |
Trong chương trình trên, c là một biến toàn cục.
Biến này có thể được truy xuất bởi cả hàm main() và test() trong chương trình trên.
Biến cục bộ static
Từ khóa static được dùng để xác định một biến static. Ví dụ:
... .. ...
int main()
{
static float a;
... .. ...
}
Biến cục bộ static chỉ tồn tại trong hàm mà nó được khai báo (giống với biến cục bộ) nhưng thời gian tồn tại của nó là từ khi hàm được gọi cho tới khi chương trình kết thúc.
Sự khác biệt lớn nhất giữa biến cục bộ và biến static đó là giá trị của biến static sẽ được giữ nguyên cho tới khi chương trình kết thúc.
Ví dụ 3: Biến cục bộ static
#include <iostream>
using namespace std;
void test()
{
// var là một biến static
static int var = 0;
++var;
cout << var << endl;
}
int main()
{
test();
test();
return 0;
}
Đầu ra
1
2 |
Trong chương trình trên, hàm test() được gọi 2 lần.
Trong lần gọi đầu tiên, biến var được khai báo là một biến static và được khởi tạo bằng 0. Sau đó 1 được cộng thêm vào var và được hiển thị trên màn hình.
Khi hàm test() trả về, biến var vẫn tồn tại vì nó là một biến static.
Trong lần gọi thứ hai, không có biến var mới nào được tạo. Biến var trước đó được tăng lên 1 và hiển thị ra màn hình.
Đầu ra của chương trình trên nếu var không được khai báo là biến static
1
1 |
Biến thanh ghi (đã không còn trong C++11)
Từ khóa register được sử dụng để xác định biến thanh ghi.
Biến thanh ghi tương tự với biến tự động và chỉ tồn tại bên trong một hàm cụ thể. Nó được cho là nhanh hơn so với biến cục bộ.
Nếu một chương trình bắt gặp một biến thanh ghi, nó sẽ lưu biến vào trong thanh thi của vi xử lý chứ không phải là trong bộ nhớ nếu có thể. Điều này giúp nó sẽ được xử lý nhanh hơn so với biến cục bộ.
Tuy nhiên, từ khóa này đã không còn trong C++11 và không nên sử dụng.
Lưu trữ cục bộ theo luồng
Lưu trữ cục bộ theo luồng là một cơ chế mà ở đó các biến được cấp phát theo hướng chỉ có một thực thể biến đối với mỗi luồng đang có.
Từ khóa thread_local được sử dụng cho mục đích này.