Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C++

Tại sao biến toàn cục (global)不好 trong C/C++

Biến toàn cục được khai báo ngoài mọi hàm. Chúng tồn tại suốt vòng đời chương trình và truy cập được từ mọi nơi.

Tại sao biến toàn cục (non-const) là "ác"?

1. Làm giảm tính module (Modularity)

Hàm phụ thuộc vào trạng thái ẩn bên ngoài thay vì tham số đầu vào. Khó tái sử dụng, khó test đơn vị.

2. Gây ra race condition (Đa luồng)

Nhiều thread truy cập/sửa đổi không đồng bộ → data race. Cần mutex/atomic phức tạp.

3. Khó debug và theo dõi

Bất kỳ hàm nào cũng có thể thay đổi giá trị. Khó biết ai, khi nào, tại sao giá trị thay đổi.

4. Naming collision (Va chạm tên)

Biến toàn cục cùng tên trong file khác → linker error hoặc hành vi không xác định.

5. Khó tối ưu hóa cho compiler

Compiler không thể giả định giá trị không đổi giữa các lời gọi hàm (alias analysis khó).

6. Thứ tự khởi tạo không xác định (Static Initialization Order Fiasco)

Biến toàn cục trong các file khác nhau: thứ tự khởi tạo không đảm bảo.

Ví dụ minh họa vấn đề

#include <stdio.h>

int g_var;      // Biến toàn cục
static int g_var1; // Static global (internal linkage)

int main() {
    int a = 15, b = 20;
    g_var = a + b;   // Hàm main sửa biến toàn cục
    g_var1 = a - b;
    
    printf("a = %d\nb = %d\ng_var = %d\ng_var1 = %d\n", a, b, g_var, g_var1);
    return 0;
}

Kết quả

a = 15
b = 20
g_var = 35
g_var1 = -5

Giải pháp thay thế

1. Biến cục bộ + tham số (Khuyến nghị nhất)

int add(int a, int b) { return a + b; } // Thuần túy, dễ test

2. Singleton / Dependency Injection

class Config {
    static Config& instance() { static Config inst; return inst; }
    int value;
private:
    Config() : value(42) {}
};
// Truy cập: Config::instance().value

3. Namespace + static (Internal linkage)

// file.cpp
namespace {
    int internal_var = 0; // Chỉ nhìn thấy trong file này
}

4. Prefix naming convention

int g_configValue; // g_ prefix cảnh báo: "cẩn thận - global"

5. constexpr / const (Biến toàn cục bất biến - AN TOÀN)

constexpr double PI = 3.14159;      // Compile-time constant
const int MAX_CONNECTIONS = 100;    // Read-only, safe

Khi nào CÓ THỂ dùng global?

  • Hằng số compile-time (constexpr, const)
  • Embedded systems: register ánh xạ hardware (volatile)
  • Logger singleton, plugin registry
  • C API callback context (opaque pointer)

Tóm tắt

Tránh biến toàn cục non-const. Dùng local variable, parameter passing, RAII, dependency injection. Code sẽ dễ test, dễ bảo trì, an toàn thread, và compiler tối ưu tốt hơn.