Câu trả lời:
Thời gian tồn tại của các static
biến hàm bắt đầu lần đầu tiên [0] luồng chương trình gặp phải khai báo và nó kết thúc khi kết thúc chương trình. Điều này có nghĩa là thời gian chạy phải thực hiện một số lưu giữ sách để phá hủy nó chỉ khi nó thực sự được xây dựng.
Ngoài ra, do tiêu chuẩn nói rằng các bộ phá hủy của các đối tượng tĩnh phải chạy theo thứ tự ngược lại khi hoàn thành công trình của chúng [1] và thứ tự xây dựng có thể phụ thuộc vào chương trình cụ thể, nên phải tính đến thứ tự xây dựng .
Thí dụ
struct emitter {
string str;
emitter(const string& s) : str(s) { cout << "Created " << str << endl; }
~emitter() { cout << "Destroyed " << str << endl; }
};
void foo(bool skip_first)
{
if (!skip_first)
static emitter a("in if");
static emitter b("in foo");
}
int main(int argc, char*[])
{
foo(argc != 2);
if (argc == 3)
foo(false);
}
Đầu ra:
C:> sample.exe
Được tạo trong foo
Bị phá hủy trong fooC:> sample.exe 1
Được tạo trong if
Được tạo trong foo
Bị phá hủy trong foo
Bị phá hủy trong ifC:> sample.exe 1 2
Tạo trong foo
Được tạo trong nếu
Bị hủy trong nếu
Bị hủy trong foo
[0]
Vì C ++ 98 [2] không có tham chiếu đến nhiều luồng nên điều này sẽ hoạt động như thế nào trong môi trường đa luồng là không xác định và có thể gây rắc rối như Roddy đề cập.
[1]
C ++ 98 phần 3.6.3.1
[basic.start.term]
[2]
Trong C ++ 11 statics được khởi tạo theo cách an toàn cho chủ đề, điều này còn được gọi là Magic Statics .
[basic.start.term]
Motti nói đúng về trật tự, nhưng có một số điều khác cần xem xét:
Trình biên dịch thường sử dụng biến cờ ẩn để cho biết liệu trạng thái cục bộ đã được khởi tạo chưa và cờ này được kiểm tra trên mỗi mục nhập của hàm. Rõ ràng đây là một thành tích nhỏ, nhưng điều đáng quan tâm hơn là cờ này không được đảm bảo an toàn cho chuỗi.
Nếu bạn có một tĩnh cục bộ như trên và foo
được gọi từ nhiều luồng, bạn có thể có các điều kiện chủng tộc gây ra plonk
được khởi tạo không chính xác hoặc thậm chí nhiều lần. Ngoài ra, trong trường hợp nàyplonk
có thể bị phá hủy bởi một luồng khác với luồng đã xây dựng nó.
Bất chấp những gì tiêu chuẩn nói, tôi rất cảnh giác với trật tự phá hủy tĩnh cục bộ thực sự, bởi vì có thể bạn vô tình dựa vào một tĩnh vẫn có hiệu lực sau khi nó bị phá hủy, và điều này thực sự rất khó để theo dõi.
Các giải thích hiện tại không thực sự hoàn chỉnh nếu không có quy tắc thực tế từ Tiêu chuẩn, được tìm thấy trong 6.7:
Việc khởi tạo bằng không của tất cả các biến phạm vi khối với thời lượng lưu trữ tĩnh hoặc thời gian lưu trữ luồng được thực hiện trước khi bất kỳ khởi tạo nào khác diễn ra. Khởi tạo liên tục của một thực thể phạm vi khối với thời gian lưu trữ tĩnh, nếu có thể, được thực hiện trước khi khối đầu tiên được nhập. Việc triển khai được phép thực hiện khởi tạo sớm các biến phạm vi khối khác với thời lượng lưu trữ tĩnh hoặc luồng trong cùng điều kiện triển khai được phép khởi tạo tĩnh một biến với thời lượng lưu trữ tĩnh hoặc luồng trong phạm vi không gian tên. Mặt khác, một biến như vậy được khởi tạo khi điều khiển lần đầu tiên đi qua khai báo của nó; một biến như vậy được coi là khởi tạo khi hoàn thành khởi tạo. Nếu khởi tạo thoát bằng cách ném một ngoại lệ, việc khởi tạo chưa hoàn tất, vì vậy nó sẽ được thử lại lần sau khi điều khiển tiếp theo đi vào khai báo. Nếu điều khiển đi vào khai báo đồng thời trong khi biến đang được khởi tạo, thì việc thực thi đồng thời sẽ chờ hoàn thành việc khởi tạo. Nếu điều khiển nhập lại khai báo một cách đệ quy trong khi biến đang được khởi tạo, hành vi không được xác định.
FWIW, Codegear C ++ Builder không phá hủy theo thứ tự dự kiến theo tiêu chuẩn.
C:\> sample.exe 1 2
Created in foo
Created in if
Destroyed in foo
Destroyed in if
... đó là một lý do khác để không dựa vào lệnh hủy diệt!
Các biến tĩnh được sử dụng khi quá trình thực thi chương trình bắt đầu và nó vẫn khả dụng cho đến khi việc thực hiện chương trình kết thúc.
Các biến tĩnh được tạo trong Phân đoạn dữ liệu của bộ nhớ .